From 68d41f23ce8d049d05bdd96889d3a2504e7f21f0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 29 Sep 2014 17:21:56 +0200 Subject: pinctrl: nomadik: force-convert to generic mux bindings This converts the Nomadik pin controller and all associated device trees to use the standard, generic mux bindings for pin controllers. There are no such device trees deployed in the wild so this is safe to do to set a good example. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 746db6a..dec72f2 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1520,12 +1520,13 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, unsigned long configs = 0; bool has_config = 0; struct property *prop; - const char *group, *gpio_name; struct device_node *np_config; - ret = of_property_read_string(np, "ste,function", &function); + ret = of_property_read_string(np, "function", &function); if (ret >= 0) { - ret = of_property_count_strings(np, "ste,pins"); + const char *group; + + ret = of_property_count_strings(np, "groups"); if (ret < 0) goto exit; @@ -1535,7 +1536,7 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; - of_property_for_each_string(np, "ste,pins", prop, group) { + of_property_for_each_string(np, "groups", prop, group) { ret = nmk_dt_add_map_mux(map, reserved_maps, num_maps, group, function); if (ret < 0) @@ -1548,6 +1549,9 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (np_config) has_config |= nmk_pinctrl_dt_get_config(np_config, &configs); if (has_config) { + const char *gpio_name; + const char *pin; + ret = of_property_count_strings(np, "ste,pins"); if (ret < 0) goto exit; @@ -1557,8 +1561,8 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; - of_property_for_each_string(np, "ste,pins", prop, group) { - gpio_name = nmk_find_pin_name(pctldev, group); + of_property_for_each_string(np, "ste,pins", prop, pin) { + gpio_name = nmk_find_pin_name(pctldev, pin); ret = nmk_dt_add_map_configs(map, reserved_maps, num_maps, -- cgit v1.1 From 51d39936acba666774b596829277db3e13e5e970 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 30 Sep 2014 12:10:11 +0200 Subject: pinctrl: abx500: force-convert to generic mux bindings This converts the ABx500 pin controller and all associated device trees to use the standard, generic mux bindings for pin controllers. There are no such device trees deployed in the wild so this is safe to do to set a good example. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-abx500.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 2289728..d0c0454 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -893,12 +893,13 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, unsigned int nconfigs = 0; bool has_config = 0; struct property *prop; - const char *group, *gpio_name; struct device_node *np_config; - ret = of_property_read_string(np, "ste,function", &function); + ret = of_property_read_string(np, "function", &function); if (ret >= 0) { - ret = of_property_count_strings(np, "ste,pins"); + const char *group; + + ret = of_property_count_strings(np, "groups"); if (ret < 0) goto exit; @@ -907,7 +908,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; - of_property_for_each_string(np, "ste,pins", prop, group) { + of_property_for_each_string(np, "groups", prop, group) { ret = abx500_dt_add_map_mux(map, reserved_maps, num_maps, group, function); if (ret < 0) @@ -927,6 +928,9 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, has_config |= nconfigs; } if (has_config) { + const char *gpio_name; + const char *pin; + ret = of_property_count_strings(np, "ste,pins"); if (ret < 0) goto exit; @@ -937,8 +941,8 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; - of_property_for_each_string(np, "ste,pins", prop, group) { - gpio_name = abx500_find_pin_name(pctldev, group); + of_property_for_each_string(np, "ste,pins", prop, pin) { + gpio_name = abx500_find_pin_name(pctldev, pin); ret = abx500_dt_add_map_configs(map, reserved_maps, num_maps, gpio_name, configs, 1); -- cgit v1.1 From 1637d480f873ca305f7f090e3b3bc92430b5892f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 30 Sep 2014 12:16:25 +0200 Subject: pinctrl: nomadik: force-convert to generic config bindings This converts the Nomadik pin controller and all associated device trees to use the standard, generic config bindings for pin controllers. There are no such device trees deployed in the wild so this is safe to do to set a good example. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index dec72f2..ad99ba8 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1552,7 +1552,7 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, const char *gpio_name; const char *pin; - ret = of_property_count_strings(np, "ste,pins"); + ret = of_property_count_strings(np, "pins"); if (ret < 0) goto exit; ret = pinctrl_utils_reserve_map(pctldev, map, @@ -1561,7 +1561,7 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; - of_property_for_each_string(np, "ste,pins", prop, pin) { + of_property_for_each_string(np, "pins", prop, pin) { gpio_name = nmk_find_pin_name(pctldev, pin); ret = nmk_dt_add_map_configs(map, reserved_maps, -- cgit v1.1 From 0564f7d946efc2948999cc26cc0831fdf81c895e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 30 Sep 2014 12:19:40 +0200 Subject: pinctrl: abx500: force-convert to generic config bindings This converts the ABx500 pin controller and all associated device trees to use the standard, generic config bindings for pin controllers. There are no such device trees deployed in the wild so this is safe to do to set a good example. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-abx500.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index d0c0454..7130cd6 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -931,7 +931,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, const char *gpio_name; const char *pin; - ret = of_property_count_strings(np, "ste,pins"); + ret = of_property_count_strings(np, "pins"); if (ret < 0) goto exit; @@ -941,7 +941,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; - of_property_for_each_string(np, "ste,pins", prop, pin) { + of_property_for_each_string(np, "pins", prop, pin) { gpio_name = abx500_find_pin_name(pctldev, pin); ret = abx500_dt_add_map_configs(map, reserved_maps, -- cgit v1.1 From eea11b0baa63ed871e16ca4513db56341e4c3598 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 30 Sep 2014 12:23:15 +0200 Subject: pinctrl: abx500: retire phandle config mechanism The abx500 pin control driver supported a method of fetching the generic config from a phandle to a separate node using the "ste,config" as a phandle. This is not used in any device trees and not documented in the bindings, so drop this support. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-abx500.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 7130cd6..acd17a2 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -891,9 +891,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, const char *function = NULL; unsigned long *configs; unsigned int nconfigs = 0; - bool has_config = 0; struct property *prop; - struct device_node *np_config; ret = of_property_read_string(np, "function", &function); if (ret >= 0) { @@ -917,17 +915,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, } ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs); - if (nconfigs) - has_config = 1; - np_config = of_parse_phandle(np, "ste,config", 0); - if (np_config) { - ret = pinconf_generic_parse_dt_config(np_config, &configs, - &nconfigs); - if (ret) - goto exit; - has_config |= nconfigs; - } - if (has_config) { + if (nconfigs) { const char *gpio_name; const char *pin; -- cgit v1.1 From 71ca917a60738731b0609abea8f3e320e43cb0a1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 30 Sep 2014 13:12:28 +0200 Subject: pinctrl: abx500: mark pin config as generic This is generic pin configuration, so add .is_generic. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-abx500.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index acd17a2..e1087c7 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -1104,6 +1104,7 @@ out: static const struct pinconf_ops abx500_pinconf_ops = { .pin_config_get = abx500_pin_config_get, .pin_config_set = abx500_pin_config_set, + .is_generic = true, }; static struct pinctrl_desc abx500_pinctrl_desc = { -- cgit v1.1 From dc603c650afdc3182df0694b4a5a0454674af18f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 18 Oct 2014 14:57:53 +0200 Subject: pinctrl: nomadik: amend MMC/SD pins There is a missing MMC/SD pin for MCDATDIR2 which is routed as alt B, add it to the MMC/SD pin group and functions. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c index ed39dca..2cd7147 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c @@ -291,6 +291,7 @@ static const unsigned u0_a_1_pins[] = { STN8815_PIN_B4, STN8815_PIN_D5, static const unsigned mmcsd_a_1_pins[] = { STN8815_PIN_B10, STN8815_PIN_A10, STN8815_PIN_C11, STN8815_PIN_B11, STN8815_PIN_A11, STN8815_PIN_C12, STN8815_PIN_B12, STN8815_PIN_A12, STN8815_PIN_C13, STN8815_PIN_C15 }; +static const unsigned mmcsd_b_1_pins[] = { STN8815_PIN_D15 }; static const unsigned u1_a_1_pins[] = { STN8815_PIN_M2, STN8815_PIN_L1, STN8815_PIN_F3, STN8815_PIN_F2 }; static const unsigned i2c1_a_1_pins[] = { STN8815_PIN_L4, STN8815_PIN_L3 }; @@ -305,6 +306,7 @@ static const unsigned i2cusb_b_1_pins[] = { STN8815_PIN_C21, STN8815_PIN_C20 }; static const struct nmk_pingroup nmk_stn8815_groups[] = { STN8815_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A), STN8815_PIN_GROUP(mmcsd_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(mmcsd_b_1, NMK_GPIO_ALT_B), STN8815_PIN_GROUP(u1_a_1, NMK_GPIO_ALT_A), STN8815_PIN_GROUP(i2c1_a_1, NMK_GPIO_ALT_A), STN8815_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A), @@ -317,7 +319,7 @@ static const struct nmk_pingroup nmk_stn8815_groups[] = { static const char * const a##_groups[] = { b }; STN8815_FUNC_GROUPS(u0, "u0_a_1"); -STN8815_FUNC_GROUPS(mmcsd, "mmcsd_a_1"); +STN8815_FUNC_GROUPS(mmcsd, "mmcsd_a_1", "mmcsd_b_1"); STN8815_FUNC_GROUPS(u1, "u1_a_1", "u1_b_1"); STN8815_FUNC_GROUPS(i2c1, "i2c1_a_1"); STN8815_FUNC_GROUPS(i2c0, "i2c0_a_1"); -- cgit v1.1 From 2e53727658f1cfd23d4bc4a91967b7d9170d0a74 Mon Sep 17 00:00:00 2001 From: Pramod Gurav Date: Tue, 30 Sep 2014 11:39:17 +0530 Subject: pinctrl: st: Fix Sparse error This change fixes below sparse error, drivers/pinctrl/pinctrl-st.c:1515:31: error: incompatible types for operation (>) drivers/pinctrl/pinctrl-st.c:1515:31: left side has type void [noderef] *irqmux_base drivers/pinctrl/pinctrl-st.c:1515:31: right side has type int Cc: Maxime Coquelin Cc: Patrice Chotard CC: Linus Walleij Cc: Srinivas Kandagatla Signed-off-by: Pramod Gurav Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-st.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index 4b1792a..caeeb1c 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -1512,7 +1512,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info, gpio_irq, st_gpio_irq_handler); } - if (info->irqmux_base > 0 || gpio_irq > 0) { + if (info->irqmux_base || gpio_irq > 0) { err = gpiochip_irqchip_add(&bank->gpio_chip, &st_gpio_irqchip, 0, handle_simple_irq, IRQ_TYPE_LEVEL_LOW); -- cgit v1.1 From 1f2b045205ce9f54babf912c9d875d7b013e4660 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 16 Oct 2014 21:47:57 +0200 Subject: pinctrl: imx: add gpio pinmux support for vf610 Add pinmux support for GPIO for Vybrid (vf610) IOMUX controller. This is needed since direction configuration is not part of the GPIO module in Vybrid. Signed-off-by: Stefan Agner Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-imx.c | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index f244676..52f2b94 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -294,11 +294,83 @@ static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, return 0; } +static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pin_reg *pin_reg; + struct imx_pin_group *grp; + struct imx_pin *imx_pin; + unsigned int pin, group; + u32 reg; + + /* Currently implementation only for shared mux/conf register */ + if (!(info->flags & SHARE_MUX_CONF_REG)) + return -EINVAL; + + pin_reg = &info->pin_regs[offset]; + if (pin_reg->mux_reg == -1) + return -EINVAL; + + /* Find the pinctrl config with GPIO mux mode for the requested pin */ + for (group = 0; group < info->ngroups; group++) { + grp = &info->groups[group]; + for (pin = 0; pin < grp->npins; pin++) { + imx_pin = &grp->pins[pin]; + if (imx_pin->pin == offset && !imx_pin->mux_mode) + goto mux_pin; + } + } + + return -EINVAL; + +mux_pin: + reg = readl(ipctl->base + pin_reg->mux_reg); + reg &= ~(0x7 << 20); + reg |= imx_pin->config; + writel(reg, ipctl->base + pin_reg->mux_reg); + + return 0; +} + +static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool input) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pin_reg *pin_reg; + u32 reg; + + /* + * Only Vybrid has the input/output buffer enable flags (IBE/OBE) + * They are part of the shared mux/conf register. + */ + if (!(info->flags & SHARE_MUX_CONF_REG)) + return -EINVAL; + + pin_reg = &info->pin_regs[offset]; + if (pin_reg->mux_reg == -1) + return -EINVAL; + + /* IBE always enabled allows us to read the value "on the wire" */ + reg = readl(ipctl->base + pin_reg->mux_reg); + if (input) + reg &= ~0x2; + else + reg |= 0x2; + writel(reg, ipctl->base + pin_reg->mux_reg); + + return 0; +} + static const struct pinmux_ops imx_pmx_ops = { .get_functions_count = imx_pmx_get_funcs_count, .get_function_name = imx_pmx_get_func_name, .get_function_groups = imx_pmx_get_groups, .set_mux = imx_pmx_set, + .gpio_request_enable = imx_pmx_gpio_request_enable, + .gpio_set_direction = imx_pmx_gpio_set_direction, }; static int imx_pinconf_get(struct pinctrl_dev *pctldev, -- cgit v1.1 From 9067bbe5989c39bd4d482edfd4d38ad99d5b081f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 13 Oct 2014 15:50:08 -0500 Subject: pinctrl: baytrail: add missing module removal support pinctrl-baytrail driver provides a proper ->remove() method on its platform_driver definition, however there's no way, currently, to unload the driver due to missing module_exit(). This patch adds module_exit(). Signed-off-by: Felipe Balbi Acked-by: David Cohen Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-baytrail.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c index e12e5b0..3ece001 100644 --- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -612,5 +612,10 @@ static int __init byt_gpio_init(void) { return platform_driver_register(&byt_gpio_driver); } - subsys_initcall(byt_gpio_init); + +static void __exit byt_gpio_exit(void) +{ + platform_driver_unregister(&byt_gpio_driver); +} +module_exit(byt_gpio_exit); -- cgit v1.1 From c61c2d7071d865adc3bbd92dee670bcf7bf56099 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 16 Oct 2014 12:12:22 +0200 Subject: pinctrl: tegra-xusb: Don't leak configurations The pinctrl config helpers make a separate copy of the configuration, so callers must make sure to free any dynamically allocated memory that was used to store it. Signed-off-by: Thierry Reding Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-tegra-xusb.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c index 1631ec9..080ec77 100644 --- a/drivers/pinctrl/pinctrl-tegra-xusb.c +++ b/drivers/pinctrl/pinctrl-tegra-xusb.c @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -171,7 +172,7 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl, if (err == -EINVAL) continue; - return err; + goto out; } config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, value); @@ -179,7 +180,7 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl, err = pinctrl_utils_add_config(padctl->pinctrl, &configs, &num_configs, config); if (err < 0) - return err; + goto out; } if (function) @@ -190,14 +191,14 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl, err = of_property_count_strings(np, "nvidia,lanes"); if (err < 0) - return err; + goto out; reserve *= err; err = pinctrl_utils_reserve_map(padctl->pinctrl, maps, reserved_maps, num_maps, reserve); if (err < 0) - return err; + goto out; of_property_for_each_string(np, "nvidia,lanes", prop, group) { if (function) { @@ -205,7 +206,7 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl, reserved_maps, num_maps, group, function); if (err < 0) - return err; + goto out; } if (num_configs) { @@ -214,11 +215,15 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl, configs, num_configs, PIN_MAP_TYPE_CONFIGS_GROUP); if (err < 0) - return err; + goto out; } } - return 0; + err = 0; + +out: + kfree(configs); + return err; } static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl, -- cgit v1.1 From eec450713e5c5cafa9b8565c84548580080b1f64 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Thu, 16 Oct 2014 10:11:29 -0700 Subject: pinctrl: pinconf-generic: Add flag to print arguments When dumping pinconf information in debugfs, config arguments are only printed when a unit is present and the argument is != 0. For parameters like the slew rate, this does not work. The slew rate uses a driver specific format for the argument, i.e. 0 can be a valid argument and a unit is not provided for it. For that reason, add a flag to enable printing the argument instead of inferring it from the presence of a unit and the value of the argument. Signed-off-by: Soren Brinkmann Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf-generic.c | 65 ++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 29ff77f..e28ef95 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -32,30 +32,32 @@ struct pin_config_item { const enum pin_config_param param; const char * const display; const char * const format; + bool has_arg; }; -#define PCONFDUMP(a, b, c) { .param = a, .display = b, .format = c } +#define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \ + .has_arg = d } static struct pin_config_item conf_items[] = { - PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL), - PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL), - PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL), - PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL), - PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL), + PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), + PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false), + PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL, false), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL, false), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, - "input bias pull to pin specific state", NULL), - PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL), - PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL), - PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL), - PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"), - PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL), - PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL), - PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL), - PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"), - PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"), - PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL), - PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"), - PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level"), + "input bias pull to pin specific state", NULL, false), + PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false), + PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL, false), + PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false), + PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true), + PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false), + PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL, false), + PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false), + PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true), + PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector", true), + PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL, true), + PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode", true), + PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true), }; void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, @@ -85,11 +87,14 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, seq_puts(s, " "); seq_puts(s, conf_items[i].display); /* Print unit if available */ - if (conf_items[i].format && - pinconf_to_config_argument(config) != 0) - seq_printf(s, " (%u %s)", - pinconf_to_config_argument(config), - conf_items[i].format); + if (conf_items[i].has_arg) { + seq_printf(s, " (%u", + pinconf_to_config_argument(config)); + if (conf_items[i].format) + seq_printf(s, " %s)", conf_items[i].format); + else + seq_puts(s, ")"); + } } } @@ -121,10 +126,14 @@ void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, seq_puts(s, " "); seq_puts(s, conf_items[i].display); /* Print unit if available */ - if (conf_items[i].format && config != 0) - seq_printf(s, " (%u %s)", - pinconf_to_config_argument(config), - conf_items[i].format); + if (conf_items[i].has_arg) { + seq_printf(s, " (%u", + pinconf_to_config_argument(config)); + if (conf_items[i].format) + seq_printf(s, " %s)", conf_items[i].format); + else + seq_puts(s, ")"); + } } } -- cgit v1.1 From aa2c35e5a66194f36578345a23708851935bdff6 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 21 Oct 2014 14:36:59 +0530 Subject: pinctrl-tb10x: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-tb10x.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c index 3b9bfcf..9363563 100644 --- a/drivers/pinctrl/pinctrl-tb10x.c +++ b/drivers/pinctrl/pinctrl-tb10x.c @@ -759,7 +759,7 @@ static struct pinctrl_desc tb10x_pindesc = { static int tb10x_pinctrl_probe(struct platform_device *pdev) { int ret = -EINVAL; - struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *mem; struct device *dev = &pdev->dev; struct device_node *of_node = dev->of_node; struct device_node *child; @@ -771,11 +771,6 @@ static int tb10x_pinctrl_probe(struct platform_device *pdev) return -EINVAL; } - if (!mem) { - dev_err(dev, "No memory resource defined.\n"); - return -EINVAL; - } - state = devm_kzalloc(dev, sizeof(struct tb10x_pinctrl) + of_get_child_count(of_node) * sizeof(struct tb10x_of_pinfunc), @@ -787,6 +782,7 @@ static int tb10x_pinctrl_probe(struct platform_device *pdev) state->pinfuncs = (struct tb10x_of_pinfunc *)(state + 1); mutex_init(&state->mutex); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); state->base = devm_ioremap_resource(dev, mem); if (IS_ERR(state->base)) { ret = PTR_ERR(state->base); -- cgit v1.1 From c654b6bf2cda7e051d1d5ba7e696855511f1105a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 17 Oct 2014 11:49:40 +0200 Subject: pinctrl: at91: use own header Copy the mach/at91_pio.h header locally and use it for pinctrl-at91.c. This allows to remove the dependency on mach/at91_pio.h to be able to move at91 to multiplatform. Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-at91.c | 4 +-- drivers/pinctrl/pinctrl-at91.h | 72 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 drivers/pinctrl/pinctrl-at91.h (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 354a81d..94643bb 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -25,9 +25,7 @@ /* Since we request GPIOs from ourself */ #include -#include -#include - +#include "pinctrl-at91.h" #include "core.h" #define MAX_GPIO_BANKS 5 diff --git a/drivers/pinctrl/pinctrl-at91.h b/drivers/pinctrl/pinctrl-at91.h new file mode 100644 index 0000000..79b957f --- /dev/null +++ b/drivers/pinctrl/pinctrl-at91.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Parallel I/O Controller (PIO) - System peripherals registers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __PINCTRL_AT91_H +#define __PINCTRL_AT91_H + +#define PIO_PER 0x00 /* Enable Register */ +#define PIO_PDR 0x04 /* Disable Register */ +#define PIO_PSR 0x08 /* Status Register */ +#define PIO_OER 0x10 /* Output Enable Register */ +#define PIO_ODR 0x14 /* Output Disable Register */ +#define PIO_OSR 0x18 /* Output Status Register */ +#define PIO_IFER 0x20 /* Glitch Input Filter Enable */ +#define PIO_IFDR 0x24 /* Glitch Input Filter Disable */ +#define PIO_IFSR 0x28 /* Glitch Input Filter Status */ +#define PIO_SODR 0x30 /* Set Output Data Register */ +#define PIO_CODR 0x34 /* Clear Output Data Register */ +#define PIO_ODSR 0x38 /* Output Data Status Register */ +#define PIO_PDSR 0x3c /* Pin Data Status Register */ +#define PIO_IER 0x40 /* Interrupt Enable Register */ +#define PIO_IDR 0x44 /* Interrupt Disable Register */ +#define PIO_IMR 0x48 /* Interrupt Mask Register */ +#define PIO_ISR 0x4c /* Interrupt Status Register */ +#define PIO_MDER 0x50 /* Multi-driver Enable Register */ +#define PIO_MDDR 0x54 /* Multi-driver Disable Register */ +#define PIO_MDSR 0x58 /* Multi-driver Status Register */ +#define PIO_PUDR 0x60 /* Pull-up Disable Register */ +#define PIO_PUER 0x64 /* Pull-up Enable Register */ +#define PIO_PUSR 0x68 /* Pull-up Status Register */ +#define PIO_ASR 0x70 /* Peripheral A Select Register */ +#define PIO_ABCDSR1 0x70 /* Peripheral ABCD Select Register 1 [some sam9 only] */ +#define PIO_BSR 0x74 /* Peripheral B Select Register */ +#define PIO_ABCDSR2 0x74 /* Peripheral ABCD Select Register 2 [some sam9 only] */ +#define PIO_ABSR 0x78 /* AB Status Register */ +#define PIO_IFSCDR 0x80 /* Input Filter Slow Clock Disable Register */ +#define PIO_IFSCER 0x84 /* Input Filter Slow Clock Enable Register */ +#define PIO_IFSCSR 0x88 /* Input Filter Slow Clock Status Register */ +#define PIO_SCDR 0x8c /* Slow Clock Divider Debouncing Register */ +#define PIO_SCDR_DIV (0x3fff << 0) /* Slow Clock Divider Mask */ +#define PIO_PPDDR 0x90 /* Pad Pull-down Disable Register */ +#define PIO_PPDER 0x94 /* Pad Pull-down Enable Register */ +#define PIO_PPDSR 0x98 /* Pad Pull-down Status Register */ +#define PIO_OWER 0xa0 /* Output Write Enable Register */ +#define PIO_OWDR 0xa4 /* Output Write Disable Register */ +#define PIO_OWSR 0xa8 /* Output Write Status Register */ +#define PIO_AIMER 0xb0 /* Additional Interrupt Modes Enable Register */ +#define PIO_AIMDR 0xb4 /* Additional Interrupt Modes Disable Register */ +#define PIO_AIMMR 0xb8 /* Additional Interrupt Modes Mask Register */ +#define PIO_ESR 0xc0 /* Edge Select Register */ +#define PIO_LSR 0xc4 /* Level Select Register */ +#define PIO_ELSR 0xc8 /* Edge/Level Status Register */ +#define PIO_FELLSR 0xd0 /* Falling Edge/Low Level Select Register */ +#define PIO_REHLSR 0xd4 /* Rising Edge/ High Level Select Register */ +#define PIO_FRLHSR 0xd8 /* Fall/Rise - Low/High Status Register */ +#define PIO_SCHMITT 0x100 /* Schmitt Trigger Register */ + +#define SAMA5D3_PIO_DRIVER1 0x118 /*PIO Driver 1 register offset*/ +#define SAMA5D3_PIO_DRIVER2 0x11C /*PIO Driver 2 register offset*/ + +#define AT91SAM9X5_PIO_DRIVER1 0x114 /*PIO Driver 1 register offset*/ +#define AT91SAM9X5_PIO_DRIVER2 0x118 /*PIO Driver 2 register offset*/ + +#endif -- cgit v1.1 From eadff3024472f8a7955fae7e5484d235ed407453 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Wed, 22 Oct 2014 12:58:46 +0300 Subject: pinctrl: Qualcomm SPMI PMIC GPIO pin controller driver This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm GPIO sub-function blocks found in the PMIC chips. Signed-off-by: Ivan T. Ivanov Acked-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/Kconfig | 13 + drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 933 +++++++++++++++++++++++++++++++ 3 files changed, 947 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-spmi-gpio.c (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 81275af..3cd243c 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -47,4 +47,17 @@ config PINCTRL_MSM8X74 This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm TLMM block found in the Qualcomm 8974 platform. +config PINCTRL_QCOM_SPMI_PMIC + tristate "Qualcomm SPMI PMIC pin controller driver" + depends on GPIOLIB && OF && SPMI + select REGMAP_SPMI + select PINMUX + select PINCONF + select GENERIC_PINCONF + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips, + which are using SPMI for communication with SoC. Example PMIC's + devices are pm8841, pm8941 and pma8084. + endif diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index ba8519f..9b49c65a 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PINCTRL_APQ8084) += pinctrl-apq8084.o obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o +obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c new file mode 100644 index 0000000..b863b50 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -0,0 +1,933 @@ +/* + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../core.h" +#include "../pinctrl-utils.h" + +#define PMIC_GPIO_ADDRESS_RANGE 0x100 + +/* type and subtype registers base address offsets */ +#define PMIC_GPIO_REG_TYPE 0x4 +#define PMIC_GPIO_REG_SUBTYPE 0x5 + +/* GPIO peripheral type and subtype out_values */ +#define PMIC_GPIO_TYPE 0x10 +#define PMIC_GPIO_SUBTYPE_GPIO_4CH 0x1 +#define PMIC_GPIO_SUBTYPE_GPIOC_4CH 0x5 +#define PMIC_GPIO_SUBTYPE_GPIO_8CH 0x9 +#define PMIC_GPIO_SUBTYPE_GPIOC_8CH 0xd + +#define PMIC_MPP_REG_RT_STS 0x10 +#define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 + +/* control register base address offsets */ +#define PMIC_GPIO_REG_MODE_CTL 0x40 +#define PMIC_GPIO_REG_DIG_VIN_CTL 0x41 +#define PMIC_GPIO_REG_DIG_PULL_CTL 0x42 +#define PMIC_GPIO_REG_DIG_OUT_CTL 0x45 +#define PMIC_GPIO_REG_EN_CTL 0x46 + +/* PMIC_GPIO_REG_MODE_CTL */ +#define PMIC_GPIO_REG_MODE_VALUE_SHIFT 0x1 +#define PMIC_GPIO_REG_MODE_FUNCTION_SHIFT 1 +#define PMIC_GPIO_REG_MODE_FUNCTION_MASK 0x7 +#define PMIC_GPIO_REG_MODE_DIR_SHIFT 4 +#define PMIC_GPIO_REG_MODE_DIR_MASK 0x7 + +/* PMIC_GPIO_REG_DIG_VIN_CTL */ +#define PMIC_GPIO_REG_VIN_SHIFT 0 +#define PMIC_GPIO_REG_VIN_MASK 0x7 + +/* PMIC_GPIO_REG_DIG_PULL_CTL */ +#define PMIC_GPIO_REG_PULL_SHIFT 0 +#define PMIC_GPIO_REG_PULL_MASK 0x7 + +#define PMIC_GPIO_PULL_DOWN 4 +#define PMIC_GPIO_PULL_DISABLE 5 + +/* PMIC_GPIO_REG_DIG_OUT_CTL */ +#define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT 0 +#define PMIC_GPIO_REG_OUT_STRENGTH_MASK 0x3 +#define PMIC_GPIO_REG_OUT_TYPE_SHIFT 4 +#define PMIC_GPIO_REG_OUT_TYPE_MASK 0x3 + +/* + * Output type - indicates pin should be configured as push-pull, + * open drain or open source. + */ +#define PMIC_GPIO_OUT_BUF_CMOS 0 +#define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS 1 +#define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS 2 + +/* PMIC_GPIO_REG_EN_CTL */ +#define PMIC_GPIO_REG_MASTER_EN_SHIFT 7 + +#define PMIC_GPIO_PHYSICAL_OFFSET 1 + +/* Qualcomm specific pin configurations */ +#define PMIC_GPIO_CONF_PULL_UP (PIN_CONFIG_END + 1) +#define PMIC_GPIO_CONF_STRENGTH (PIN_CONFIG_END + 2) + +/** + * struct pmic_gpio_pad - keep current GPIO settings + * @base: Address base in SPMI device. + * @irq: IRQ number which this GPIO generate. + * @is_enabled: Set to false when GPIO should be put in high Z state. + * @out_value: Cached pin output value + * @have_buffer: Set to true if GPIO output could be configured in push-pull, + * open-drain or open-source mode. + * @output_enabled: Set to true if GPIO output logic is enabled. + * @input_enabled: Set to true if GPIO input buffer logic is enabled. + * @num_sources: Number of power-sources supported by this GPIO. + * @power_source: Current power-source used. + * @buffer_type: Push-pull, open-drain or open-source. + * @pullup: Constant current which flow trough GPIO output buffer. + * @strength: No, Low, Medium, High + * @function: See pmic_gpio_functions[] + */ +struct pmic_gpio_pad { + u16 base; + int irq; + bool is_enabled; + bool out_value; + bool have_buffer; + bool output_enabled; + bool input_enabled; + unsigned int num_sources; + unsigned int power_source; + unsigned int buffer_type; + unsigned int pullup; + unsigned int strength; + unsigned int function; +}; + +struct pmic_gpio_state { + struct device *dev; + struct regmap *map; + struct pinctrl_dev *ctrl; + struct gpio_chip chip; +}; + +struct pmic_gpio_bindings { + const char *property; + unsigned param; +}; + +static struct pmic_gpio_bindings pmic_gpio_bindings[] = { + {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP}, + {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH}, +}; + +static const char *const pmic_gpio_groups[] = { + "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", + "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", + "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", + "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", +}; + +static const char *const pmic_gpio_functions[] = { + PMIC_GPIO_FUNC_NORMAL, PMIC_GPIO_FUNC_PAIRED, + PMIC_GPIO_FUNC_FUNC1, PMIC_GPIO_FUNC_FUNC2, + PMIC_GPIO_FUNC_DTEST1, PMIC_GPIO_FUNC_DTEST2, + PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4, +}; + +static inline struct pmic_gpio_state *to_gpio_state(struct gpio_chip *chip) +{ + return container_of(chip, struct pmic_gpio_state, chip); +}; + +static int pmic_gpio_read(struct pmic_gpio_state *state, + struct pmic_gpio_pad *pad, unsigned int addr) +{ + unsigned int val; + int ret; + + ret = regmap_read(state->map, pad->base + addr, &val); + if (ret < 0) + dev_err(state->dev, "read 0x%x failed\n", addr); + else + ret = val; + + return ret; +} + +static int pmic_gpio_write(struct pmic_gpio_state *state, + struct pmic_gpio_pad *pad, unsigned int addr, + unsigned int val) +{ + int ret; + + ret = regmap_write(state->map, pad->base + addr, val); + if (ret < 0) + dev_err(state->dev, "write 0x%x failed\n", addr); + + return ret; +} + +static int pmic_gpio_get_groups_count(struct pinctrl_dev *pctldev) +{ + /* Every PIN is a group */ + return pctldev->desc->npins; +} + +static const char *pmic_gpio_get_group_name(struct pinctrl_dev *pctldev, + unsigned pin) +{ + return pctldev->desc->pins[pin].name; +} + +static int pmic_gpio_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin, + const unsigned **pins, unsigned *num_pins) +{ + *pins = &pctldev->desc->pins[pin].number; + *num_pins = 1; + return 0; +} + +static int pmic_gpio_parse_dt_config(struct device_node *np, + struct pinctrl_dev *pctldev, + unsigned long **configs, + unsigned int *nconfs) +{ + struct pmic_gpio_bindings *par; + unsigned long cfg; + int ret, i; + u32 val; + + for (i = 0; i < ARRAY_SIZE(pmic_gpio_bindings); i++) { + par = &pmic_gpio_bindings[i]; + ret = of_property_read_u32(np, par->property, &val); + + /* property not found */ + if (ret == -EINVAL) + continue; + + /* use zero as default value */ + if (ret) + val = 0; + + dev_dbg(pctldev->dev, "found %s with value %u\n", + par->property, val); + + cfg = pinconf_to_config_packed(par->param, val); + + ret = pinctrl_utils_add_config(pctldev, configs, nconfs, cfg); + if (ret) + return ret; + } + + return 0; +} + +static int pmic_gpio_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserv, unsigned *nmaps, + enum pinctrl_map_type type) +{ + unsigned long *configs = NULL; + unsigned nconfs = 0; + struct property *prop; + const char *group; + int ret; + + ret = pmic_gpio_parse_dt_config(np, pctldev, &configs, &nconfs); + if (ret < 0) + return ret; + + if (!nconfs) + return 0; + + ret = of_property_count_strings(np, "pins"); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_reserve_map(pctldev, map, reserv, nmaps, ret); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "pins", prop, group) { + ret = pinctrl_utils_add_map_configs(pctldev, map, + reserv, nmaps, group, + configs, nconfs, type); + if (ret < 0) + break; + } +exit: + kfree(configs); + return ret; +} + +static int pmic_gpio_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *nmaps) +{ + enum pinctrl_map_type type; + struct device_node *np; + unsigned reserv; + int ret; + + ret = 0; + *map = NULL; + *nmaps = 0; + reserv = 0; + type = PIN_MAP_TYPE_CONFIGS_GROUP; + + for_each_child_of_node(np_config, np) { + ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, + &reserv, nmaps, type); + if (ret) + break; + + ret = pmic_gpio_dt_subnode_to_map(pctldev, np, map, &reserv, + nmaps, type); + if (ret) + break; + } + + if (ret < 0) + pinctrl_utils_dt_free_map(pctldev, *map, *nmaps); + + return ret; +} + +static const struct pinctrl_ops pmic_gpio_pinctrl_ops = { + .get_groups_count = pmic_gpio_get_groups_count, + .get_group_name = pmic_gpio_get_group_name, + .get_group_pins = pmic_gpio_get_group_pins, + .dt_node_to_map = pmic_gpio_dt_node_to_map, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int pmic_gpio_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(pmic_gpio_functions); +} + +static const char *pmic_gpio_get_function_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + return pmic_gpio_functions[function]; +} + +static int pmic_gpio_get_function_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char *const **groups, + unsigned *const num_qgroups) +{ + *groups = pmic_gpio_groups; + *num_qgroups = pctldev->desc->npins; + return 0; +} + +static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function, + unsigned pin) +{ + struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); + struct pmic_gpio_pad *pad; + unsigned int val; + int ret; + + pad = pctldev->desc->pins[pin].drv_data; + + pad->function = function; + + val = 0; + if (pad->output_enabled) { + if (pad->input_enabled) + val = 2; + else + val = 1; + } + + val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; + val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + + ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; + + val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT; + + return pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val); +} + +static const struct pinmux_ops pmic_gpio_pinmux_ops = { + .get_functions_count = pmic_gpio_get_functions_count, + .get_function_name = pmic_gpio_get_function_name, + .get_function_groups = pmic_gpio_get_function_groups, + .set_mux = pmic_gpio_set_mux, +}; + +static int pmic_gpio_config_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + unsigned param = pinconf_to_config_param(*config); + struct pmic_gpio_pad *pad; + unsigned arg; + + pad = pctldev->desc->pins[pin].drv_data; + + switch (param) { + case PIN_CONFIG_DRIVE_PUSH_PULL: + arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_CMOS; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS; + break; + case PIN_CONFIG_DRIVE_OPEN_SOURCE: + arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + arg = pad->pullup == PMIC_GPIO_PULL_DOWN; + break; + case PIN_CONFIG_BIAS_DISABLE: + arg = pad->pullup = PMIC_GPIO_PULL_DISABLE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + arg = pad->pullup == PMIC_GPIO_PULL_UP_30; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + arg = !pad->is_enabled; + break; + case PIN_CONFIG_POWER_SOURCE: + arg = pad->power_source; + break; + case PIN_CONFIG_INPUT_ENABLE: + arg = pad->input_enabled; + break; + case PIN_CONFIG_OUTPUT: + arg = pad->out_value; + break; + case PMIC_GPIO_CONF_PULL_UP: + arg = pad->pullup; + break; + case PMIC_GPIO_CONF_STRENGTH: + arg = pad->strength; + break; + default: + return -EINVAL; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned nconfs) +{ + struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); + struct pmic_gpio_pad *pad; + unsigned param, arg; + unsigned int val; + int i, ret; + + pad = pctldev->desc->pins[pin].drv_data; + + for (i = 0; i < nconfs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_DRIVE_PUSH_PULL: + pad->buffer_type = PMIC_GPIO_OUT_BUF_CMOS; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (!pad->have_buffer) + return -EINVAL; + pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS; + break; + case PIN_CONFIG_DRIVE_OPEN_SOURCE: + if (!pad->have_buffer) + return -EINVAL; + pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS; + break; + case PIN_CONFIG_BIAS_DISABLE: + pad->pullup = PMIC_GPIO_PULL_DISABLE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + pad->pullup = PMIC_GPIO_PULL_UP_30; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (arg) + pad->pullup = PMIC_GPIO_PULL_DOWN; + else + pad->pullup = PMIC_GPIO_PULL_DISABLE; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + pad->is_enabled = false; + break; + case PIN_CONFIG_POWER_SOURCE: + if (arg > pad->num_sources) + return -EINVAL; + pad->power_source = arg; + break; + case PIN_CONFIG_INPUT_ENABLE: + pad->input_enabled = arg ? true : false; + break; + case PIN_CONFIG_OUTPUT: + pad->output_enabled = true; + pad->out_value = arg; + break; + case PMIC_GPIO_CONF_PULL_UP: + if (arg > PMIC_GPIO_PULL_UP_1P5_30) + return -EINVAL; + pad->pullup = arg; + break; + case PMIC_GPIO_CONF_STRENGTH: + if (arg > PMIC_GPIO_STRENGTH_LOW) + return -EINVAL; + pad->strength = arg; + break; + default: + return -EINVAL; + } + } + + val = pad->power_source << PMIC_GPIO_REG_VIN_SHIFT; + + ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL, val); + if (ret < 0) + return ret; + + val = pad->pullup << PMIC_GPIO_REG_PULL_SHIFT; + + ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL, val); + if (ret < 0) + return ret; + + val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT; + val = pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; + + ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val); + if (ret < 0) + return ret; + + val = 0; + if (pad->output_enabled) { + if (pad->input_enabled) + val = 2; + else + val = 1; + } + + val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; + val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; + val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + + return pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); +} + +static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin) +{ + struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); + struct pmic_gpio_pad *pad; + int ret, val; + + static const char *const biases[] = { + "pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA", + "pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull" + }; + static const char *const buffer_types[] = { + "push-pull", "open-drain", "open-source" + }; + static const char *const strengths[] = { + "no", "high", "medium", "low" + }; + + pad = pctldev->desc->pins[pin].drv_data; + + seq_printf(s, " gpio%-2d:", pin + PMIC_GPIO_PHYSICAL_OFFSET); + + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL); + + if (val < 0 || !(val >> PMIC_GPIO_REG_MASTER_EN_SHIFT)) { + seq_puts(s, " ---"); + } else { + + if (!pad->input_enabled) { + ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS); + if (!ret) { + ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; + pad->out_value = ret; + } + } + + seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); + seq_printf(s, " %-7s", pmic_gpio_functions[pad->function]); + seq_printf(s, " vin-%d", pad->power_source); + seq_printf(s, " %-27s", biases[pad->pullup]); + seq_printf(s, " %-10s", buffer_types[pad->buffer_type]); + seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); + seq_printf(s, " %-7s", strengths[pad->strength]); + } +} + +static const struct pinconf_ops pmic_gpio_pinconf_ops = { + .pin_config_group_get = pmic_gpio_config_get, + .pin_config_group_set = pmic_gpio_config_set, + .pin_config_group_dbg_show = pmic_gpio_config_dbg_show, +}; + +static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin) +{ + struct pmic_gpio_state *state = to_gpio_state(chip); + unsigned long config; + + config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1); + + return pmic_gpio_config_set(state->ctrl, pin, &config, 1); +} + +static int pmic_gpio_direction_output(struct gpio_chip *chip, + unsigned pin, int val) +{ + struct pmic_gpio_state *state = to_gpio_state(chip); + unsigned long config; + + config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val); + + return pmic_gpio_config_set(state->ctrl, pin, &config, 1); +} + +static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin) +{ + struct pmic_gpio_state *state = to_gpio_state(chip); + struct pmic_gpio_pad *pad; + int ret; + + pad = state->ctrl->desc->pins[pin].drv_data; + + if (!pad->is_enabled) + return -EINVAL; + + if (pad->input_enabled) { + ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS); + if (ret < 0) + return ret; + + pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK; + } + + return pad->out_value; +} + +static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value) +{ + struct pmic_gpio_state *state = to_gpio_state(chip); + unsigned long config; + + config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value); + + pmic_gpio_config_set(state->ctrl, pin, &config, 1); +} + +static int pmic_gpio_request(struct gpio_chip *chip, unsigned base) +{ + return pinctrl_request_gpio(chip->base + base); +} + +static void pmic_gpio_free(struct gpio_chip *chip, unsigned base) +{ + pinctrl_free_gpio(chip->base + base); +} + +static int pmic_gpio_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpio_desc, + u32 *flags) +{ + if (chip->of_gpio_n_cells < 2) + return -EINVAL; + + if (flags) + *flags = gpio_desc->args[1]; + + return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET; +} + +static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin) +{ + struct pmic_gpio_state *state = to_gpio_state(chip); + struct pmic_gpio_pad *pad; + + pad = state->ctrl->desc->pins[pin].drv_data; + + return pad->irq; +} + +static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct pmic_gpio_state *state = to_gpio_state(chip); + unsigned i; + + for (i = 0; i < chip->ngpio; i++) { + pmic_gpio_config_dbg_show(state->ctrl, s, i); + seq_puts(s, "\n"); + } +} + +static const struct gpio_chip pmic_gpio_gpio_template = { + .direction_input = pmic_gpio_direction_input, + .direction_output = pmic_gpio_direction_output, + .get = pmic_gpio_get, + .set = pmic_gpio_set, + .request = pmic_gpio_request, + .free = pmic_gpio_free, + .of_xlate = pmic_gpio_of_xlate, + .to_irq = pmic_gpio_to_irq, + .dbg_show = pmic_gpio_dbg_show, +}; + +static int pmic_gpio_populate(struct pmic_gpio_state *state, + struct pmic_gpio_pad *pad) +{ + int type, subtype, val, dir; + + type = pmic_gpio_read(state, pad, PMIC_GPIO_REG_TYPE); + if (type < 0) + return type; + + if (type != PMIC_GPIO_TYPE) { + dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n", + type, pad->base); + return -ENODEV; + } + + subtype = pmic_gpio_read(state, pad, PMIC_GPIO_REG_SUBTYPE); + if (subtype < 0) + return subtype; + + switch (subtype) { + case PMIC_GPIO_SUBTYPE_GPIO_4CH: + pad->have_buffer = true; + case PMIC_GPIO_SUBTYPE_GPIOC_4CH: + pad->num_sources = 4; + break; + case PMIC_GPIO_SUBTYPE_GPIO_8CH: + pad->have_buffer = true; + case PMIC_GPIO_SUBTYPE_GPIOC_8CH: + pad->num_sources = 8; + break; + default: + dev_err(state->dev, "unknown GPIO type 0x%x\n", subtype); + return -ENODEV; + } + + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); + if (val < 0) + return val; + + pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + + dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT; + dir &= PMIC_GPIO_REG_MODE_DIR_MASK; + switch (dir) { + case 0: + pad->input_enabled = true; + pad->output_enabled = false; + break; + case 1: + pad->input_enabled = false; + pad->output_enabled = true; + break; + case 2: + pad->input_enabled = true; + pad->output_enabled = true; + break; + default: + dev_err(state->dev, "unknown GPIO direction\n"); + return -ENODEV; + } + + pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; + pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK; + + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL); + if (val < 0) + return val; + + pad->power_source = val >> PMIC_GPIO_REG_VIN_SHIFT; + pad->power_source &= PMIC_GPIO_REG_VIN_MASK; + + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL); + if (val < 0) + return val; + + pad->pullup = val >> PMIC_GPIO_REG_PULL_SHIFT; + pad->pullup &= PMIC_GPIO_REG_PULL_MASK; + + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL); + if (val < 0) + return val; + + pad->strength = val >> PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; + pad->strength &= PMIC_GPIO_REG_OUT_STRENGTH_MASK; + + pad->buffer_type = val >> PMIC_GPIO_REG_OUT_TYPE_SHIFT; + pad->buffer_type &= PMIC_GPIO_REG_OUT_TYPE_MASK; + + /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */ + pad->is_enabled = true; + return 0; +} + +static int pmic_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pinctrl_pin_desc *pindesc; + struct pinctrl_desc *pctrldesc; + struct pmic_gpio_pad *pad, *pads; + struct pmic_gpio_state *state; + int ret, npins, i; + u32 res[2]; + + ret = of_property_read_u32_array(dev->of_node, "reg", res, 2); + if (ret < 0) { + dev_err(dev, "missing base address and/or range"); + return ret; + } + + npins = res[1] / PMIC_GPIO_ADDRESS_RANGE; + + if (!npins) + return -EINVAL; + + BUG_ON(npins > ARRAY_SIZE(pmic_gpio_groups)); + + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + platform_set_drvdata(pdev, state); + + state->dev = &pdev->dev; + state->map = dev_get_regmap(dev->parent, NULL); + + pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL); + if (!pindesc) + return -ENOMEM; + + pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL); + if (!pads) + return -ENOMEM; + + pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL); + if (!pctrldesc) + return -ENOMEM; + + pctrldesc->pctlops = &pmic_gpio_pinctrl_ops; + pctrldesc->pmxops = &pmic_gpio_pinmux_ops; + pctrldesc->confops = &pmic_gpio_pinconf_ops; + pctrldesc->owner = THIS_MODULE; + pctrldesc->name = dev_name(dev); + pctrldesc->pins = pindesc; + pctrldesc->npins = npins; + + for (i = 0; i < npins; i++, pindesc++) { + pad = &pads[i]; + pindesc->drv_data = pad; + pindesc->number = i; + pindesc->name = pmic_gpio_groups[i]; + + pad->irq = platform_get_irq(pdev, i); + if (pad->irq < 0) + return pad->irq; + + pad->base = res[0] + i * PMIC_GPIO_ADDRESS_RANGE; + + ret = pmic_gpio_populate(state, pad); + if (ret < 0) + return ret; + } + + state->chip = pmic_gpio_gpio_template; + state->chip.dev = dev; + state->chip.base = -1; + state->chip.ngpio = npins; + state->chip.label = dev_name(dev); + state->chip.of_gpio_n_cells = 2; + state->chip.can_sleep = false; + + state->ctrl = pinctrl_register(pctrldesc, dev, state); + if (!state->ctrl) + return -ENODEV; + + ret = gpiochip_add(&state->chip); + if (ret) { + dev_err(state->dev, "can't add gpio chip\n"); + goto err_chip; + } + + ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins); + if (ret) { + dev_err(dev, "failed to add pin range\n"); + goto err_range; + } + + return 0; + +err_range: + gpiochip_remove(&state->chip); +err_chip: + pinctrl_unregister(state->ctrl); + return ret; +} + +static int pmic_gpio_remove(struct platform_device *pdev) +{ + struct pmic_gpio_state *state = platform_get_drvdata(pdev); + + gpiochip_remove(&state->chip); + pinctrl_unregister(state->ctrl); + return 0; +} + +static const struct of_device_id pmic_gpio_of_match[] = { + { .compatible = "qcom,pm8941-gpio" }, /* 36 GPIO's */ + { .compatible = "qcom,pma8084-gpio" }, /* 22 GPIO's */ + { }, +}; + +MODULE_DEVICE_TABLE(of, pmic_gpio_of_match); + +static struct platform_driver pmic_gpio_driver = { + .driver = { + .name = "qcom-spmi-gpio", + .of_match_table = pmic_gpio_of_match, + }, + .probe = pmic_gpio_probe, + .remove = pmic_gpio_remove, +}; + +module_platform_driver(pmic_gpio_driver); + +MODULE_AUTHOR("Ivan T. Ivanov "); +MODULE_DESCRIPTION("Qualcomm SPMI PMIC GPIO pin control driver"); +MODULE_ALIAS("platform:qcom-spmi-gpio"); +MODULE_LICENSE("GPL v2"); -- cgit v1.1 From cfb24f6ebd38137ebf072cb5629fdf6df51e49c1 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Wed, 22 Oct 2014 12:58:47 +0300 Subject: pinctrl: Qualcomm SPMI PMIC MPP pin controller driver This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm MPP sub-function blocks found in the PMIC chips. Signed-off-by: Ivan T. Ivanov Acked-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 949 ++++++++++++++++++++++++++++++++ 2 files changed, 950 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-spmi-mpp.c (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 9b49c65a..bfd79af 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o +obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c new file mode 100644 index 0000000..a8924db --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -0,0 +1,949 @@ +/* + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../core.h" +#include "../pinctrl-utils.h" + +#define PMIC_MPP_ADDRESS_RANGE 0x100 + +/* + * Pull Up Values - it indicates whether a pull-up should be + * applied for bidirectional mode only. The hardware ignores the + * configuration when operating in other modes. + */ +#define PMIC_MPP_PULL_UP_0P6KOHM 0 +#define PMIC_MPP_PULL_UP_10KOHM 1 +#define PMIC_MPP_PULL_UP_30KOHM 2 +#define PMIC_MPP_PULL_UP_OPEN 3 + +/* type registers base address bases */ +#define PMIC_MPP_REG_TYPE 0x4 +#define PMIC_MPP_REG_SUBTYPE 0x5 + +/* mpp peripheral type and subtype values */ +#define PMIC_MPP_TYPE 0x11 +#define PMIC_MPP_SUBTYPE_4CH_NO_ANA_OUT 0x3 +#define PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT 0x4 +#define PMIC_MPP_SUBTYPE_4CH_NO_SINK 0x5 +#define PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK 0x6 +#define PMIC_MPP_SUBTYPE_4CH_FULL_FUNC 0x7 +#define PMIC_MPP_SUBTYPE_8CH_FULL_FUNC 0xf + +#define PMIC_MPP_REG_RT_STS 0x10 +#define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 + +/* control register base address bases */ +#define PMIC_MPP_REG_MODE_CTL 0x40 +#define PMIC_MPP_REG_DIG_VIN_CTL 0x41 +#define PMIC_MPP_REG_DIG_PULL_CTL 0x42 +#define PMIC_MPP_REG_DIG_IN_CTL 0x43 +#define PMIC_MPP_REG_EN_CTL 0x46 +#define PMIC_MPP_REG_AIN_CTL 0x4a + +/* PMIC_MPP_REG_MODE_CTL */ +#define PMIC_MPP_REG_MODE_VALUE_MASK 0x1 +#define PMIC_MPP_REG_MODE_FUNCTION_SHIFT 1 +#define PMIC_MPP_REG_MODE_FUNCTION_MASK 0x7 +#define PMIC_MPP_REG_MODE_DIR_SHIFT 4 +#define PMIC_MPP_REG_MODE_DIR_MASK 0x7 + +/* PMIC_MPP_REG_DIG_VIN_CTL */ +#define PMIC_MPP_REG_VIN_SHIFT 0 +#define PMIC_MPP_REG_VIN_MASK 0x7 + +/* PMIC_MPP_REG_DIG_PULL_CTL */ +#define PMIC_MPP_REG_PULL_SHIFT 0 +#define PMIC_MPP_REG_PULL_MASK 0x7 + +/* PMIC_MPP_REG_EN_CTL */ +#define PMIC_MPP_REG_MASTER_EN_SHIFT 7 + +/* PMIC_MPP_REG_AIN_CTL */ +#define PMIC_MPP_REG_AIN_ROUTE_SHIFT 0 +#define PMIC_MPP_REG_AIN_ROUTE_MASK 0x7 + +#define PMIC_MPP_PHYSICAL_OFFSET 1 + +/* Qualcomm specific pin configurations */ +#define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1) +#define PMIC_MPP_CONF_ANALOG_MODE (PIN_CONFIG_END + 2) + +/** + * struct pmic_mpp_pad - keep current MPP settings + * @base: Address base in SPMI device. + * @irq: IRQ number which this MPP generate. + * @is_enabled: Set to false when MPP should be put in high Z state. + * @out_value: Cached pin output value. + * @output_enabled: Set to true if MPP output logic is enabled. + * @input_enabled: Set to true if MPP input buffer logic is enabled. + * @analog_mode: Set to true when MPP should operate in Analog Input, Analog + * Output or Bidirectional Analog mode. + * @num_sources: Number of power-sources supported by this MPP. + * @power_source: Current power-source used. + * @amux_input: Set the source for analog input. + * @pullup: Pullup resistor value. Valid in Bidirectional mode only. + * @function: See pmic_mpp_functions[]. + */ +struct pmic_mpp_pad { + u16 base; + int irq; + bool is_enabled; + bool out_value; + bool output_enabled; + bool input_enabled; + bool analog_mode; + unsigned int num_sources; + unsigned int power_source; + unsigned int amux_input; + unsigned int pullup; + unsigned int function; +}; + +struct pmic_mpp_state { + struct device *dev; + struct regmap *map; + struct pinctrl_dev *ctrl; + struct gpio_chip chip; +}; + +struct pmic_mpp_bindings { + const char *property; + unsigned param; +}; + +static struct pmic_mpp_bindings pmic_mpp_bindings[] = { + {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE}, + {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE}, +}; + +static const char *const pmic_mpp_groups[] = { + "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8", +}; + +static const char *const pmic_mpp_functions[] = { + PMIC_MPP_FUNC_NORMAL, PMIC_MPP_FUNC_PAIRED, + "reserved1", "reserved2", + PMIC_MPP_FUNC_DTEST1, PMIC_MPP_FUNC_DTEST2, + PMIC_MPP_FUNC_DTEST3, PMIC_MPP_FUNC_DTEST4, +}; + +static inline struct pmic_mpp_state *to_mpp_state(struct gpio_chip *chip) +{ + return container_of(chip, struct pmic_mpp_state, chip); +}; + +static int pmic_mpp_read(struct pmic_mpp_state *state, + struct pmic_mpp_pad *pad, unsigned int addr) +{ + unsigned int val; + int ret; + + ret = regmap_read(state->map, pad->base + addr, &val); + if (ret < 0) + dev_err(state->dev, "read 0x%x failed\n", addr); + else + ret = val; + + return ret; +} + +static int pmic_mpp_write(struct pmic_mpp_state *state, + struct pmic_mpp_pad *pad, unsigned int addr, + unsigned int val) +{ + int ret; + + ret = regmap_write(state->map, pad->base + addr, val); + if (ret < 0) + dev_err(state->dev, "write 0x%x failed\n", addr); + + return ret; +} + +static int pmic_mpp_get_groups_count(struct pinctrl_dev *pctldev) +{ + /* Every PIN is a group */ + return pctldev->desc->npins; +} + +static const char *pmic_mpp_get_group_name(struct pinctrl_dev *pctldev, + unsigned pin) +{ + return pctldev->desc->pins[pin].name; +} + +static int pmic_mpp_get_group_pins(struct pinctrl_dev *pctldev, + unsigned pin, + const unsigned **pins, unsigned *num_pins) +{ + *pins = &pctldev->desc->pins[pin].number; + *num_pins = 1; + return 0; +} + +static int pmic_mpp_parse_dt_config(struct device_node *np, + struct pinctrl_dev *pctldev, + unsigned long **configs, + unsigned int *nconfs) +{ + struct pmic_mpp_bindings *par; + unsigned long cfg; + int ret, i; + u32 val; + + for (i = 0; i < ARRAY_SIZE(pmic_mpp_bindings); i++) { + par = &pmic_mpp_bindings[i]; + ret = of_property_read_u32(np, par->property, &val); + + /* property not found */ + if (ret == -EINVAL) + continue; + + /* use zero as default value, when no value is specified */ + if (ret) + val = 0; + + dev_dbg(pctldev->dev, "found %s with value %u\n", + par->property, val); + + cfg = pinconf_to_config_packed(par->param, val); + + ret = pinctrl_utils_add_config(pctldev, configs, nconfs, cfg); + if (ret) + return ret; + } + + return 0; +} + +static int pmic_mpp_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserv, unsigned *nmaps, + enum pinctrl_map_type type) +{ + unsigned long *configs = NULL; + unsigned nconfs = 0; + struct property *prop; + const char *group; + int ret; + + ret = pmic_mpp_parse_dt_config(np, pctldev, &configs, &nconfs); + if (ret < 0) + return ret; + + if (!nconfs) + return 0; + + ret = of_property_count_strings(np, "pins"); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_reserve_map(pctldev, map, reserv, nmaps, ret); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "pins", prop, group) { + ret = pinctrl_utils_add_map_configs(pctldev, map, + reserv, nmaps, group, + configs, nconfs, type); + if (ret < 0) + break; + } +exit: + kfree(configs); + return ret; +} + +static int pmic_mpp_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *nmaps) +{ + struct device_node *np; + enum pinctrl_map_type type; + unsigned reserv; + int ret; + + ret = 0; + *map = NULL; + *nmaps = 0; + reserv = 0; + type = PIN_MAP_TYPE_CONFIGS_GROUP; + + for_each_child_of_node(np_config, np) { + ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, + &reserv, nmaps, type); + if (ret) + break; + + ret = pmic_mpp_dt_subnode_to_map(pctldev, np, map, &reserv, + nmaps, type); + if (ret) + break; + } + + if (ret < 0) + pinctrl_utils_dt_free_map(pctldev, *map, *nmaps); + + return ret; +} + +static const struct pinctrl_ops pmic_mpp_pinctrl_ops = { + .get_groups_count = pmic_mpp_get_groups_count, + .get_group_name = pmic_mpp_get_group_name, + .get_group_pins = pmic_mpp_get_group_pins, + .dt_node_to_map = pmic_mpp_dt_node_to_map, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int pmic_mpp_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(pmic_mpp_functions); +} + +static const char *pmic_mpp_get_function_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + return pmic_mpp_functions[function]; +} + +static int pmic_mpp_get_function_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char *const **groups, + unsigned *const num_qgroups) +{ + *groups = pmic_mpp_groups; + *num_qgroups = pctldev->desc->npins; + return 0; +} + +static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, + unsigned pin) +{ + struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); + struct pmic_mpp_pad *pad; + unsigned int val; + int ret; + + pad = pctldev->desc->pins[pin].drv_data; + + pad->function = function; + + if (!pad->analog_mode) { + val = 0; /* just digital input */ + if (pad->output_enabled) { + if (pad->input_enabled) + val = 2; /* digital input and output */ + else + val = 1; /* just digital output */ + } + } else { + val = 4; /* just analog input */ + if (pad->output_enabled) { + if (pad->input_enabled) + val = 3; /* analog input and output */ + else + val = 5; /* just analog output */ + } + } + + val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; + val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; + + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); + if (ret < 0) + return ret; + + val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; + + return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val); +} + +static const struct pinmux_ops pmic_mpp_pinmux_ops = { + .get_functions_count = pmic_mpp_get_functions_count, + .get_function_name = pmic_mpp_get_function_name, + .get_function_groups = pmic_mpp_get_function_groups, + .set_mux = pmic_mpp_set_mux, +}; + +static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + unsigned param = pinconf_to_config_param(*config); + struct pmic_mpp_pad *pad; + unsigned arg = 0; + + pad = pctldev->desc->pins[pin].drv_data; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + arg = pad->pullup == PMIC_MPP_PULL_UP_OPEN; + break; + case PIN_CONFIG_BIAS_PULL_UP: + switch (pad->pullup) { + case PMIC_MPP_PULL_UP_OPEN: + arg = 0; + break; + case PMIC_MPP_PULL_UP_0P6KOHM: + arg = 600; + break; + case PMIC_MPP_PULL_UP_10KOHM: + arg = 10000; + break; + case PMIC_MPP_PULL_UP_30KOHM: + arg = 30000; + break; + default: + return -EINVAL; + } + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + arg = !pad->is_enabled; + break; + case PIN_CONFIG_POWER_SOURCE: + arg = pad->power_source; + break; + case PIN_CONFIG_INPUT_ENABLE: + arg = pad->input_enabled; + break; + case PIN_CONFIG_OUTPUT: + arg = pad->out_value; + break; + case PMIC_MPP_CONF_AMUX_ROUTE: + arg = pad->amux_input; + break; + case PMIC_MPP_CONF_ANALOG_MODE: + arg = pad->analog_mode; + break; + default: + return -EINVAL; + } + + /* Convert register value to pinconf value */ + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned nconfs) +{ + struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); + struct pmic_mpp_pad *pad; + unsigned param, arg; + unsigned int val; + int i, ret; + + pad = pctldev->desc->pins[pin].drv_data; + + for (i = 0; i < nconfs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + pad->pullup = PMIC_MPP_PULL_UP_OPEN; + break; + case PIN_CONFIG_BIAS_PULL_UP: + switch (arg) { + case 600: + pad->pullup = PMIC_MPP_PULL_UP_0P6KOHM; + break; + case 10000: + pad->pullup = PMIC_MPP_PULL_UP_10KOHM; + break; + case 30000: + pad->pullup = PMIC_MPP_PULL_UP_30KOHM; + break; + default: + return -EINVAL; + } + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + pad->is_enabled = false; + break; + case PIN_CONFIG_POWER_SOURCE: + if (arg >= pad->num_sources) + return -EINVAL; + pad->power_source = arg; + break; + case PIN_CONFIG_INPUT_ENABLE: + pad->input_enabled = arg ? true : false; + break; + case PIN_CONFIG_OUTPUT: + pad->output_enabled = true; + pad->out_value = arg; + break; + case PMIC_MPP_CONF_AMUX_ROUTE: + if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4) + return -EINVAL; + pad->amux_input = arg; + break; + case PMIC_MPP_CONF_ANALOG_MODE: + pad->analog_mode = true; + break; + default: + return -EINVAL; + } + } + + val = pad->power_source << PMIC_MPP_REG_VIN_SHIFT; + + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_VIN_CTL, val); + if (ret < 0) + return ret; + + val = pad->pullup << PMIC_MPP_REG_PULL_SHIFT; + + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_PULL_CTL, val); + if (ret < 0) + return ret; + + val = pad->amux_input & PMIC_MPP_REG_AIN_ROUTE_MASK; + + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_AIN_CTL, val); + if (ret < 0) + return ret; + + if (!pad->analog_mode) { + val = 0; /* just digital input */ + if (pad->output_enabled) { + if (pad->input_enabled) + val = 2; /* digital input and output */ + else + val = 1; /* just digital output */ + } + } else { + val = 4; /* just analog input */ + if (pad->output_enabled) { + if (pad->input_enabled) + val = 3; /* analog input and output */ + else + val = 5; /* just analog output */ + } + } + + val = val << PMIC_MPP_REG_MODE_DIR_SHIFT; + val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; + val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; + + return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); +} + +static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin) +{ + struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); + struct pmic_mpp_pad *pad; + int ret, val; + + static const char *const biases[] = { + "0.6kOhm", "10kOhm", "30kOhm", "Disabled" + }; + + + pad = pctldev->desc->pins[pin].drv_data; + + seq_printf(s, " mpp%-2d:", pin + PMIC_MPP_PHYSICAL_OFFSET); + + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); + + if (val < 0 || !(val >> PMIC_MPP_REG_MASTER_EN_SHIFT)) { + seq_puts(s, " ---"); + } else { + + if (pad->input_enabled) { + ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS); + if (!ret) { + ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; + pad->out_value = ret; + } + } + + seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); + seq_printf(s, " %-4s", pad->analog_mode ? "ana" : "dig"); + seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]); + seq_printf(s, " vin-%d", pad->power_source); + seq_printf(s, " %-8s", biases[pad->pullup]); + seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); + } +} + +static const struct pinconf_ops pmic_mpp_pinconf_ops = { + .pin_config_group_get = pmic_mpp_config_get, + .pin_config_group_set = pmic_mpp_config_set, + .pin_config_group_dbg_show = pmic_mpp_config_dbg_show, +}; + +static int pmic_mpp_direction_input(struct gpio_chip *chip, unsigned pin) +{ + struct pmic_mpp_state *state = to_mpp_state(chip); + unsigned long config; + + config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1); + + return pmic_mpp_config_set(state->ctrl, pin, &config, 1); +} + +static int pmic_mpp_direction_output(struct gpio_chip *chip, + unsigned pin, int val) +{ + struct pmic_mpp_state *state = to_mpp_state(chip); + unsigned long config; + + config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val); + + return pmic_mpp_config_set(state->ctrl, pin, &config, 1); +} + +static int pmic_mpp_get(struct gpio_chip *chip, unsigned pin) +{ + struct pmic_mpp_state *state = to_mpp_state(chip); + struct pmic_mpp_pad *pad; + int ret; + + pad = state->ctrl->desc->pins[pin].drv_data; + + if (pad->input_enabled) { + ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS); + if (ret < 0) + return ret; + + pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK; + } + + return pad->out_value; +} + +static void pmic_mpp_set(struct gpio_chip *chip, unsigned pin, int value) +{ + struct pmic_mpp_state *state = to_mpp_state(chip); + unsigned long config; + + config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value); + + pmic_mpp_config_set(state->ctrl, pin, &config, 1); +} + +static int pmic_mpp_request(struct gpio_chip *chip, unsigned base) +{ + return pinctrl_request_gpio(chip->base + base); +} + +static void pmic_mpp_free(struct gpio_chip *chip, unsigned base) +{ + pinctrl_free_gpio(chip->base + base); +} + +static int pmic_mpp_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpio_desc, + u32 *flags) +{ + if (chip->of_gpio_n_cells < 2) + return -EINVAL; + + if (flags) + *flags = gpio_desc->args[1]; + + return gpio_desc->args[0] - PMIC_MPP_PHYSICAL_OFFSET; +} + +static int pmic_mpp_to_irq(struct gpio_chip *chip, unsigned pin) +{ + struct pmic_mpp_state *state = to_mpp_state(chip); + struct pmic_mpp_pad *pad; + + pad = state->ctrl->desc->pins[pin].drv_data; + + return pad->irq; +} + +static void pmic_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct pmic_mpp_state *state = to_mpp_state(chip); + unsigned i; + + for (i = 0; i < chip->ngpio; i++) { + pmic_mpp_config_dbg_show(state->ctrl, s, i); + seq_puts(s, "\n"); + } +} + +static const struct gpio_chip pmic_mpp_gpio_template = { + .direction_input = pmic_mpp_direction_input, + .direction_output = pmic_mpp_direction_output, + .get = pmic_mpp_get, + .set = pmic_mpp_set, + .request = pmic_mpp_request, + .free = pmic_mpp_free, + .of_xlate = pmic_mpp_of_xlate, + .to_irq = pmic_mpp_to_irq, + .dbg_show = pmic_mpp_dbg_show, +}; + +static int pmic_mpp_populate(struct pmic_mpp_state *state, + struct pmic_mpp_pad *pad) +{ + int type, subtype, val, dir; + + type = pmic_mpp_read(state, pad, PMIC_MPP_REG_TYPE); + if (type < 0) + return type; + + if (type != PMIC_MPP_TYPE) { + dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n", + type, pad->base); + return -ENODEV; + } + + subtype = pmic_mpp_read(state, pad, PMIC_MPP_REG_SUBTYPE); + if (subtype < 0) + return subtype; + + switch (subtype) { + case PMIC_MPP_SUBTYPE_4CH_NO_ANA_OUT: + case PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT: + case PMIC_MPP_SUBTYPE_4CH_NO_SINK: + case PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK: + case PMIC_MPP_SUBTYPE_4CH_FULL_FUNC: + pad->num_sources = 4; + break; + case PMIC_MPP_SUBTYPE_8CH_FULL_FUNC: + pad->num_sources = 8; + break; + default: + dev_err(state->dev, "unknown MPP type 0x%x at 0x%x\n", + subtype, pad->base); + return -ENODEV; + } + + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_MODE_CTL); + if (val < 0) + return val; + + pad->out_value = val & PMIC_MPP_REG_MODE_VALUE_MASK; + + dir = val >> PMIC_MPP_REG_MODE_DIR_SHIFT; + dir &= PMIC_MPP_REG_MODE_DIR_MASK; + + switch (dir) { + case 0: + pad->input_enabled = true; + pad->output_enabled = false; + pad->analog_mode = false; + break; + case 1: + pad->input_enabled = false; + pad->output_enabled = true; + pad->analog_mode = false; + break; + case 2: + pad->input_enabled = true; + pad->output_enabled = true; + pad->analog_mode = false; + break; + case 3: + pad->input_enabled = true; + pad->output_enabled = true; + pad->analog_mode = true; + break; + case 4: + pad->input_enabled = true; + pad->output_enabled = false; + pad->analog_mode = true; + break; + case 5: + pad->input_enabled = false; + pad->output_enabled = true; + pad->analog_mode = true; + break; + default: + dev_err(state->dev, "unknown MPP direction\n"); + return -ENODEV; + } + + pad->function = val >> PMIC_MPP_REG_MODE_FUNCTION_SHIFT; + pad->function &= PMIC_MPP_REG_MODE_FUNCTION_MASK; + + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_VIN_CTL); + if (val < 0) + return val; + + pad->power_source = val >> PMIC_MPP_REG_VIN_SHIFT; + pad->power_source &= PMIC_MPP_REG_VIN_MASK; + + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_PULL_CTL); + if (val < 0) + return val; + + pad->pullup = val >> PMIC_MPP_REG_PULL_SHIFT; + pad->pullup &= PMIC_MPP_REG_PULL_MASK; + + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AIN_CTL); + if (val < 0) + return val; + + pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT; + pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK; + + /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */ + pad->is_enabled = true; + return 0; +} + +static int pmic_mpp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pinctrl_pin_desc *pindesc; + struct pinctrl_desc *pctrldesc; + struct pmic_mpp_pad *pad, *pads; + struct pmic_mpp_state *state; + int ret, npins, i; + u32 res[2]; + + ret = of_property_read_u32_array(dev->of_node, "reg", res, 2); + if (ret < 0) { + dev_err(dev, "missing base address and/or range"); + return ret; + } + + npins = res[1] / PMIC_MPP_ADDRESS_RANGE; + if (!npins) + return -EINVAL; + + BUG_ON(npins > ARRAY_SIZE(pmic_mpp_groups)); + + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + platform_set_drvdata(pdev, state); + + state->dev = &pdev->dev; + state->map = dev_get_regmap(dev->parent, NULL); + + pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL); + if (!pindesc) + return -ENOMEM; + + pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL); + if (!pads) + return -ENOMEM; + + pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL); + if (!pctrldesc) + return -ENOMEM; + + pctrldesc->pctlops = &pmic_mpp_pinctrl_ops; + pctrldesc->pmxops = &pmic_mpp_pinmux_ops; + pctrldesc->confops = &pmic_mpp_pinconf_ops; + pctrldesc->owner = THIS_MODULE; + pctrldesc->name = dev_name(dev); + pctrldesc->pins = pindesc; + pctrldesc->npins = npins; + + for (i = 0; i < npins; i++, pindesc++) { + pad = &pads[i]; + pindesc->drv_data = pad; + pindesc->number = i; + pindesc->name = pmic_mpp_groups[i]; + + pad->irq = platform_get_irq(pdev, i); + if (pad->irq < 0) + return pad->irq; + + pad->base = res[0] + i * PMIC_MPP_ADDRESS_RANGE; + + ret = pmic_mpp_populate(state, pad); + if (ret < 0) + return ret; + } + + state->chip = pmic_mpp_gpio_template; + state->chip.dev = dev; + state->chip.base = -1; + state->chip.ngpio = npins; + state->chip.label = dev_name(dev); + state->chip.of_gpio_n_cells = 2; + state->chip.can_sleep = false; + + state->ctrl = pinctrl_register(pctrldesc, dev, state); + if (!state->ctrl) + return -ENODEV; + + ret = gpiochip_add(&state->chip); + if (ret) { + dev_err(state->dev, "can't add gpio chip\n"); + goto err_chip; + } + + ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins); + if (ret) { + dev_err(dev, "failed to add pin range\n"); + goto err_range; + } + + return 0; + +err_range: + gpiochip_remove(&state->chip); +err_chip: + pinctrl_unregister(state->ctrl); + return ret; +} + +static int pmic_mpp_remove(struct platform_device *pdev) +{ + struct pmic_mpp_state *state = platform_get_drvdata(pdev); + + gpiochip_remove(&state->chip); + pinctrl_unregister(state->ctrl); + return 0; +} + +static const struct of_device_id pmic_mpp_of_match[] = { + { .compatible = "qcom,pm8841-mpp" }, /* 4 MPP's */ + { .compatible = "qcom,pm8941-mpp" }, /* 8 MPP's */ + { .compatible = "qcom,pma8084-mpp" }, /* 8 MPP's */ + { }, +}; + +MODULE_DEVICE_TABLE(of, pmic_mpp_of_match); + +static struct platform_driver pmic_mpp_driver = { + .driver = { + .name = "qcom-spmi-mpp", + .of_match_table = pmic_mpp_of_match, + }, + .probe = pmic_mpp_probe, + .remove = pmic_mpp_remove, +}; + +module_platform_driver(pmic_mpp_driver); + +MODULE_AUTHOR("Ivan T. Ivanov "); +MODULE_DESCRIPTION("Qualcomm SPMI PMIC MPP pin control driver"); +MODULE_ALIAS("platform:qcom-spmi-mpp"); +MODULE_LICENSE("GPL v2"); -- cgit v1.1 From 5fae8b86fdf083bc43bf759abad6661be9d0b9ac Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 24 Oct 2014 15:16:52 +0300 Subject: pinctrl: Move Intel Baytrail pinctrl driver under intel directory We are going to have more pinctrl drivers for Intel hardware so separate all our pin controller drivers to own directory. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 13 +- drivers/pinctrl/Makefile | 2 +- drivers/pinctrl/intel/Kconfig | 15 + drivers/pinctrl/intel/Makefile | 3 + drivers/pinctrl/intel/pinctrl-baytrail.c | 621 +++++++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-baytrail.c | 621 ------------------------------- 6 files changed, 641 insertions(+), 634 deletions(-) create mode 100644 drivers/pinctrl/intel/Kconfig create mode 100644 drivers/pinctrl/intel/Makefile create mode 100644 drivers/pinctrl/intel/pinctrl-baytrail.c delete mode 100644 drivers/pinctrl/pinctrl-baytrail.c (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index c6a66de..d014f22 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -67,18 +67,6 @@ config PINCTRL_AT91 help Say Y here to enable the at91 pinctrl driver -config PINCTRL_BAYTRAIL - bool "Intel Baytrail GPIO pin control" - depends on GPIOLIB && ACPI && X86 - select GPIOLIB_IRQCHIP - help - driver for memory mapped GPIO functionality on Intel Baytrail - platforms. Supports 3 banks with 102, 28 and 44 gpios. - Most pins are usually muxed to some other functionality by firmware, - so only a small amount is available for gpio use. - - Requires ACPI device enumeration code to set up a platform device. - config PINCTRL_BCM2835 bool select PINMUX @@ -205,6 +193,7 @@ config PINCTRL_PALMAS source "drivers/pinctrl/berlin/Kconfig" source "drivers/pinctrl/freescale/Kconfig" +source "drivers/pinctrl/intel/Kconfig" source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/nomadik/Kconfig" source "drivers/pinctrl/qcom/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 51f52d3..c030b3d 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o -obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o @@ -39,6 +38,7 @@ obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-y += freescale/ +obj-$(CONFIG_X86) += intel/ obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-y += nomadik/ obj-$(CONFIG_ARCH_QCOM) += qcom/ diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig new file mode 100644 index 0000000..957c903 --- /dev/null +++ b/drivers/pinctrl/intel/Kconfig @@ -0,0 +1,15 @@ +# +# Intel pin control drivers +# + +config PINCTRL_BAYTRAIL + bool "Intel Baytrail GPIO pin control" + depends on GPIOLIB && ACPI + select GPIOLIB_IRQCHIP + help + driver for memory mapped GPIO functionality on Intel Baytrail + platforms. Supports 3 banks with 102, 28 and 44 gpios. + Most pins are usually muxed to some other functionality by firmware, + so only a small amount is available for gpio use. + + Requires ACPI device enumeration code to set up a platform device. diff --git a/drivers/pinctrl/intel/Makefile b/drivers/pinctrl/intel/Makefile new file mode 100644 index 0000000..d049b76 --- /dev/null +++ b/drivers/pinctrl/intel/Makefile @@ -0,0 +1,3 @@ +# Intel pin control drivers + +obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c new file mode 100644 index 0000000..3ece001 --- /dev/null +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -0,0 +1,621 @@ +/* + * Pinctrl GPIO driver for Intel Baytrail + * Copyright (c) 2012-2013, Intel Corporation. + * + * Author: Mathias Nyman + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* memory mapped register offsets */ +#define BYT_CONF0_REG 0x000 +#define BYT_CONF1_REG 0x004 +#define BYT_VAL_REG 0x008 +#define BYT_DFT_REG 0x00c +#define BYT_INT_STAT_REG 0x800 + +/* BYT_CONF0_REG register bits */ +#define BYT_IODEN BIT(31) +#define BYT_DIRECT_IRQ_EN BIT(27) +#define BYT_TRIG_NEG BIT(26) +#define BYT_TRIG_POS BIT(25) +#define BYT_TRIG_LVL BIT(24) +#define BYT_PULL_STR_SHIFT 9 +#define BYT_PULL_STR_MASK (3 << BYT_PULL_STR_SHIFT) +#define BYT_PULL_STR_2K (0 << BYT_PULL_STR_SHIFT) +#define BYT_PULL_STR_10K (1 << BYT_PULL_STR_SHIFT) +#define BYT_PULL_STR_20K (2 << BYT_PULL_STR_SHIFT) +#define BYT_PULL_STR_40K (3 << BYT_PULL_STR_SHIFT) +#define BYT_PULL_ASSIGN_SHIFT 7 +#define BYT_PULL_ASSIGN_MASK (3 << BYT_PULL_ASSIGN_SHIFT) +#define BYT_PULL_ASSIGN_UP (1 << BYT_PULL_ASSIGN_SHIFT) +#define BYT_PULL_ASSIGN_DOWN (2 << BYT_PULL_ASSIGN_SHIFT) +#define BYT_PIN_MUX 0x07 + +/* BYT_VAL_REG register bits */ +#define BYT_INPUT_EN BIT(2) /* 0: input enabled (active low)*/ +#define BYT_OUTPUT_EN BIT(1) /* 0: output enabled (active low)*/ +#define BYT_LEVEL BIT(0) + +#define BYT_DIR_MASK (BIT(1) | BIT(2)) +#define BYT_TRIG_MASK (BIT(26) | BIT(25) | BIT(24)) + +#define BYT_NGPIO_SCORE 102 +#define BYT_NGPIO_NCORE 28 +#define BYT_NGPIO_SUS 44 + +#define BYT_SCORE_ACPI_UID "1" +#define BYT_NCORE_ACPI_UID "2" +#define BYT_SUS_ACPI_UID "3" + +/* + * Baytrail gpio controller consist of three separate sub-controllers called + * SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID. + * + * GPIO numbering is _not_ ordered meaning that gpio # 0 in ACPI namespace does + * _not_ correspond to the first gpio register at controller's gpio base. + * There is no logic or pattern in mapping gpio numbers to registers (pads) so + * each sub-controller needs to have its own mapping table + */ + +/* score_pins[gpio_nr] = pad_nr */ + +static unsigned const score_pins[BYT_NGPIO_SCORE] = { + 85, 89, 93, 96, 99, 102, 98, 101, 34, 37, + 36, 38, 39, 35, 40, 84, 62, 61, 64, 59, + 54, 56, 60, 55, 63, 57, 51, 50, 53, 47, + 52, 49, 48, 43, 46, 41, 45, 42, 58, 44, + 95, 105, 70, 68, 67, 66, 69, 71, 65, 72, + 86, 90, 88, 92, 103, 77, 79, 83, 78, 81, + 80, 82, 13, 12, 15, 14, 17, 18, 19, 16, + 2, 1, 0, 4, 6, 7, 9, 8, 33, 32, + 31, 30, 29, 27, 25, 28, 26, 23, 21, 20, + 24, 22, 5, 3, 10, 11, 106, 87, 91, 104, + 97, 100, +}; + +static unsigned const ncore_pins[BYT_NGPIO_NCORE] = { + 19, 18, 17, 20, 21, 22, 24, 25, 23, 16, + 14, 15, 12, 26, 27, 1, 4, 8, 11, 0, + 3, 6, 10, 13, 2, 5, 9, 7, +}; + +static unsigned const sus_pins[BYT_NGPIO_SUS] = { + 29, 33, 30, 31, 32, 34, 36, 35, 38, 37, + 18, 7, 11, 20, 17, 1, 8, 10, 19, 12, + 0, 2, 23, 39, 28, 27, 22, 21, 24, 25, + 26, 51, 56, 54, 49, 55, 48, 57, 50, 58, + 52, 53, 59, 40, +}; + +static struct pinctrl_gpio_range byt_ranges[] = { + { + .name = BYT_SCORE_ACPI_UID, /* match with acpi _UID in probe */ + .npins = BYT_NGPIO_SCORE, + .pins = score_pins, + }, + { + .name = BYT_NCORE_ACPI_UID, + .npins = BYT_NGPIO_NCORE, + .pins = ncore_pins, + }, + { + .name = BYT_SUS_ACPI_UID, + .npins = BYT_NGPIO_SUS, + .pins = sus_pins, + }, + { + }, +}; + +struct byt_gpio { + struct gpio_chip chip; + struct platform_device *pdev; + spinlock_t lock; + void __iomem *reg_base; + struct pinctrl_gpio_range *range; +}; + +#define to_byt_gpio(c) container_of(c, struct byt_gpio, chip) + +static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset, + int reg) +{ + struct byt_gpio *vg = to_byt_gpio(chip); + u32 reg_offset; + + if (reg == BYT_INT_STAT_REG) + reg_offset = (offset / 32) * 4; + else + reg_offset = vg->range->pins[offset] * 16; + + return vg->reg_base + reg_offset + reg; +} + +static bool is_special_pin(struct byt_gpio *vg, unsigned offset) +{ + /* SCORE pin 92-93 */ + if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) && + offset >= 92 && offset <= 93) + return true; + + /* SUS pin 11-21 */ + if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) && + offset >= 11 && offset <= 21) + return true; + + return false; +} + +static int byt_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct byt_gpio *vg = to_byt_gpio(chip); + void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG); + u32 value; + bool special; + + /* + * In most cases, func pin mux 000 means GPIO function. + * But, some pins may have func pin mux 001 represents + * GPIO function. Only allow user to export pin with + * func pin mux preset as GPIO function by BIOS/FW. + */ + value = readl(reg) & BYT_PIN_MUX; + special = is_special_pin(vg, offset); + if ((special && value != 1) || (!special && value)) { + dev_err(&vg->pdev->dev, + "pin %u cannot be used as GPIO.\n", offset); + return -EINVAL; + } + + pm_runtime_get(&vg->pdev->dev); + + return 0; +} + +static void byt_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct byt_gpio *vg = to_byt_gpio(chip); + void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); + u32 value; + + /* clear interrupt triggering */ + value = readl(reg); + value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + writel(value, reg); + + pm_runtime_put(&vg->pdev->dev); +} + +static int byt_irq_type(struct irq_data *d, unsigned type) +{ + struct byt_gpio *vg = to_byt_gpio(irq_data_get_irq_chip_data(d)); + u32 offset = irqd_to_hwirq(d); + u32 value; + unsigned long flags; + void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); + + if (offset >= vg->chip.ngpio) + return -EINVAL; + + spin_lock_irqsave(&vg->lock, flags); + value = readl(reg); + + /* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits + * are used to indicate high and low level triggering + */ + value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + + switch (type) { + case IRQ_TYPE_LEVEL_HIGH: + value |= BYT_TRIG_LVL; + case IRQ_TYPE_EDGE_RISING: + value |= BYT_TRIG_POS; + break; + case IRQ_TYPE_LEVEL_LOW: + value |= BYT_TRIG_LVL; + case IRQ_TYPE_EDGE_FALLING: + value |= BYT_TRIG_NEG; + break; + case IRQ_TYPE_EDGE_BOTH: + value |= (BYT_TRIG_NEG | BYT_TRIG_POS); + break; + } + writel(value, reg); + + spin_unlock_irqrestore(&vg->lock, flags); + + return 0; +} + +static int byt_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); + return readl(reg) & BYT_LEVEL; +} + +static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct byt_gpio *vg = to_byt_gpio(chip); + void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); + unsigned long flags; + u32 old_val; + + spin_lock_irqsave(&vg->lock, flags); + + old_val = readl(reg); + + if (value) + writel(old_val | BYT_LEVEL, reg); + else + writel(old_val & ~BYT_LEVEL, reg); + + spin_unlock_irqrestore(&vg->lock, flags); +} + +static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct byt_gpio *vg = to_byt_gpio(chip); + void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); + unsigned long flags; + u32 value; + + spin_lock_irqsave(&vg->lock, flags); + + value = readl(reg) | BYT_DIR_MASK; + value &= ~BYT_INPUT_EN; /* active low */ + writel(value, reg); + + spin_unlock_irqrestore(&vg->lock, flags); + + return 0; +} + +static int byt_gpio_direction_output(struct gpio_chip *chip, + unsigned gpio, int value) +{ + struct byt_gpio *vg = to_byt_gpio(chip); + void __iomem *conf_reg = byt_gpio_reg(chip, gpio, BYT_CONF0_REG); + void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG); + unsigned long flags; + u32 reg_val; + + spin_lock_irqsave(&vg->lock, flags); + + /* + * Before making any direction modifications, do a check if gpio + * is set for direct IRQ. On baytrail, setting GPIO to output does + * not make sense, so let's at least warn the caller before they shoot + * themselves in the foot. + */ + WARN(readl(conf_reg) & BYT_DIRECT_IRQ_EN, + "Potential Error: Setting GPIO with direct_irq_en to output"); + + reg_val = readl(reg) | BYT_DIR_MASK; + reg_val &= ~BYT_OUTPUT_EN; + + if (value) + writel(reg_val | BYT_LEVEL, reg); + else + writel(reg_val & ~BYT_LEVEL, reg); + + spin_unlock_irqrestore(&vg->lock, flags); + + return 0; +} + +static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct byt_gpio *vg = to_byt_gpio(chip); + int i; + unsigned long flags; + u32 conf0, val, offs; + + spin_lock_irqsave(&vg->lock, flags); + + for (i = 0; i < vg->chip.ngpio; i++) { + const char *pull_str = NULL; + const char *pull = NULL; + const char *label; + offs = vg->range->pins[i] * 16; + conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG); + val = readl(vg->reg_base + offs + BYT_VAL_REG); + + label = gpiochip_is_requested(chip, i); + if (!label) + label = "Unrequested"; + + switch (conf0 & BYT_PULL_ASSIGN_MASK) { + case BYT_PULL_ASSIGN_UP: + pull = "up"; + break; + case BYT_PULL_ASSIGN_DOWN: + pull = "down"; + break; + } + + switch (conf0 & BYT_PULL_STR_MASK) { + case BYT_PULL_STR_2K: + pull_str = "2k"; + break; + case BYT_PULL_STR_10K: + pull_str = "10k"; + break; + case BYT_PULL_STR_20K: + pull_str = "20k"; + break; + case BYT_PULL_STR_40K: + pull_str = "40k"; + break; + } + + seq_printf(s, + " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s", + i, + label, + val & BYT_INPUT_EN ? " " : "in", + val & BYT_OUTPUT_EN ? " " : "out", + val & BYT_LEVEL ? "hi" : "lo", + vg->range->pins[i], offs, + conf0 & 0x7, + conf0 & BYT_TRIG_NEG ? " fall" : " ", + conf0 & BYT_TRIG_POS ? " rise" : " ", + conf0 & BYT_TRIG_LVL ? " level" : " "); + + if (pull && pull_str) + seq_printf(s, " %-4s %-3s", pull, pull_str); + else + seq_puts(s, " "); + + if (conf0 & BYT_IODEN) + seq_puts(s, " open-drain"); + + seq_puts(s, "\n"); + } + spin_unlock_irqrestore(&vg->lock, flags); +} + +static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc)); + struct irq_chip *chip = irq_data_get_irq_chip(data); + u32 base, pin, mask; + void __iomem *reg; + u32 pending; + unsigned virq; + int looplimit = 0; + + /* check from GPIO controller which pin triggered the interrupt */ + for (base = 0; base < vg->chip.ngpio; base += 32) { + + reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG); + + while ((pending = readl(reg))) { + pin = __ffs(pending); + mask = BIT(pin); + /* Clear before handling so we can't lose an edge */ + writel(mask, reg); + + virq = irq_find_mapping(vg->chip.irqdomain, base + pin); + generic_handle_irq(virq); + + /* In case bios or user sets triggering incorretly a pin + * might remain in "interrupt triggered" state. + */ + if (looplimit++ > 32) { + dev_err(&vg->pdev->dev, + "Gpio %d interrupt flood, disabling\n", + base + pin); + + reg = byt_gpio_reg(&vg->chip, base + pin, + BYT_CONF0_REG); + mask = readl(reg); + mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS | + BYT_TRIG_LVL); + writel(mask, reg); + mask = readl(reg); /* flush */ + break; + } + } + } + chip->irq_eoi(data); +} + +static void byt_irq_unmask(struct irq_data *d) +{ +} + +static void byt_irq_mask(struct irq_data *d) +{ +} + +static struct irq_chip byt_irqchip = { + .name = "BYT-GPIO", + .irq_mask = byt_irq_mask, + .irq_unmask = byt_irq_unmask, + .irq_set_type = byt_irq_type, + .flags = IRQCHIP_SKIP_SET_WAKE, +}; + +static void byt_gpio_irq_init_hw(struct byt_gpio *vg) +{ + void __iomem *reg; + u32 base, value; + + /* clear interrupt status trigger registers */ + for (base = 0; base < vg->chip.ngpio; base += 32) { + reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG); + writel(0xffffffff, reg); + /* make sure trigger bits are cleared, if not then a pin + might be misconfigured in bios */ + value = readl(reg); + if (value) + dev_err(&vg->pdev->dev, + "GPIO interrupt error, pins misconfigured\n"); + } +} + +static int byt_gpio_probe(struct platform_device *pdev) +{ + struct byt_gpio *vg; + struct gpio_chip *gc; + struct resource *mem_rc, *irq_rc; + struct device *dev = &pdev->dev; + struct acpi_device *acpi_dev; + struct pinctrl_gpio_range *range; + acpi_handle handle = ACPI_HANDLE(dev); + int ret; + + if (acpi_bus_get_device(handle, &acpi_dev)) + return -ENODEV; + + vg = devm_kzalloc(dev, sizeof(struct byt_gpio), GFP_KERNEL); + if (!vg) { + dev_err(&pdev->dev, "can't allocate byt_gpio chip data\n"); + return -ENOMEM; + } + + for (range = byt_ranges; range->name; range++) { + if (!strcmp(acpi_dev->pnp.unique_id, range->name)) { + vg->chip.ngpio = range->npins; + vg->range = range; + break; + } + } + + if (!vg->chip.ngpio || !vg->range) + return -ENODEV; + + vg->pdev = pdev; + platform_set_drvdata(pdev, vg); + + mem_rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + vg->reg_base = devm_ioremap_resource(dev, mem_rc); + if (IS_ERR(vg->reg_base)) + return PTR_ERR(vg->reg_base); + + spin_lock_init(&vg->lock); + + gc = &vg->chip; + gc->label = dev_name(&pdev->dev); + gc->owner = THIS_MODULE; + gc->request = byt_gpio_request; + gc->free = byt_gpio_free; + gc->direction_input = byt_gpio_direction_input; + gc->direction_output = byt_gpio_direction_output; + gc->get = byt_gpio_get; + gc->set = byt_gpio_set; + gc->dbg_show = byt_gpio_dbg_show; + gc->base = -1; + gc->can_sleep = false; + gc->dev = dev; + + ret = gpiochip_add(gc); + if (ret) { + dev_err(&pdev->dev, "failed adding byt-gpio chip\n"); + return ret; + } + + /* set up interrupts */ + irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (irq_rc && irq_rc->start) { + byt_gpio_irq_init_hw(vg); + ret = gpiochip_irqchip_add(gc, &byt_irqchip, 0, + handle_simple_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "failed to add irqchip\n"); + gpiochip_remove(gc); + return ret; + } + + gpiochip_set_chained_irqchip(gc, &byt_irqchip, + (unsigned)irq_rc->start, + byt_gpio_irq_handler); + } + + pm_runtime_enable(dev); + + return 0; +} + +static int byt_gpio_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int byt_gpio_runtime_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops byt_gpio_pm_ops = { + .runtime_suspend = byt_gpio_runtime_suspend, + .runtime_resume = byt_gpio_runtime_resume, +}; + +static const struct acpi_device_id byt_gpio_acpi_match[] = { + { "INT33B2", 0 }, + { "INT33FC", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match); + +static int byt_gpio_remove(struct platform_device *pdev) +{ + struct byt_gpio *vg = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + gpiochip_remove(&vg->chip); + + return 0; +} + +static struct platform_driver byt_gpio_driver = { + .probe = byt_gpio_probe, + .remove = byt_gpio_remove, + .driver = { + .name = "byt_gpio", + .owner = THIS_MODULE, + .pm = &byt_gpio_pm_ops, + .acpi_match_table = ACPI_PTR(byt_gpio_acpi_match), + }, +}; + +static int __init byt_gpio_init(void) +{ + return platform_driver_register(&byt_gpio_driver); +} +subsys_initcall(byt_gpio_init); + +static void __exit byt_gpio_exit(void) +{ + platform_driver_unregister(&byt_gpio_driver); +} +module_exit(byt_gpio_exit); diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c deleted file mode 100644 index 3ece001..0000000 --- a/drivers/pinctrl/pinctrl-baytrail.c +++ /dev/null @@ -1,621 +0,0 @@ -/* - * Pinctrl GPIO driver for Intel Baytrail - * Copyright (c) 2012-2013, Intel Corporation. - * - * Author: Mathias Nyman - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* memory mapped register offsets */ -#define BYT_CONF0_REG 0x000 -#define BYT_CONF1_REG 0x004 -#define BYT_VAL_REG 0x008 -#define BYT_DFT_REG 0x00c -#define BYT_INT_STAT_REG 0x800 - -/* BYT_CONF0_REG register bits */ -#define BYT_IODEN BIT(31) -#define BYT_DIRECT_IRQ_EN BIT(27) -#define BYT_TRIG_NEG BIT(26) -#define BYT_TRIG_POS BIT(25) -#define BYT_TRIG_LVL BIT(24) -#define BYT_PULL_STR_SHIFT 9 -#define BYT_PULL_STR_MASK (3 << BYT_PULL_STR_SHIFT) -#define BYT_PULL_STR_2K (0 << BYT_PULL_STR_SHIFT) -#define BYT_PULL_STR_10K (1 << BYT_PULL_STR_SHIFT) -#define BYT_PULL_STR_20K (2 << BYT_PULL_STR_SHIFT) -#define BYT_PULL_STR_40K (3 << BYT_PULL_STR_SHIFT) -#define BYT_PULL_ASSIGN_SHIFT 7 -#define BYT_PULL_ASSIGN_MASK (3 << BYT_PULL_ASSIGN_SHIFT) -#define BYT_PULL_ASSIGN_UP (1 << BYT_PULL_ASSIGN_SHIFT) -#define BYT_PULL_ASSIGN_DOWN (2 << BYT_PULL_ASSIGN_SHIFT) -#define BYT_PIN_MUX 0x07 - -/* BYT_VAL_REG register bits */ -#define BYT_INPUT_EN BIT(2) /* 0: input enabled (active low)*/ -#define BYT_OUTPUT_EN BIT(1) /* 0: output enabled (active low)*/ -#define BYT_LEVEL BIT(0) - -#define BYT_DIR_MASK (BIT(1) | BIT(2)) -#define BYT_TRIG_MASK (BIT(26) | BIT(25) | BIT(24)) - -#define BYT_NGPIO_SCORE 102 -#define BYT_NGPIO_NCORE 28 -#define BYT_NGPIO_SUS 44 - -#define BYT_SCORE_ACPI_UID "1" -#define BYT_NCORE_ACPI_UID "2" -#define BYT_SUS_ACPI_UID "3" - -/* - * Baytrail gpio controller consist of three separate sub-controllers called - * SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID. - * - * GPIO numbering is _not_ ordered meaning that gpio # 0 in ACPI namespace does - * _not_ correspond to the first gpio register at controller's gpio base. - * There is no logic or pattern in mapping gpio numbers to registers (pads) so - * each sub-controller needs to have its own mapping table - */ - -/* score_pins[gpio_nr] = pad_nr */ - -static unsigned const score_pins[BYT_NGPIO_SCORE] = { - 85, 89, 93, 96, 99, 102, 98, 101, 34, 37, - 36, 38, 39, 35, 40, 84, 62, 61, 64, 59, - 54, 56, 60, 55, 63, 57, 51, 50, 53, 47, - 52, 49, 48, 43, 46, 41, 45, 42, 58, 44, - 95, 105, 70, 68, 67, 66, 69, 71, 65, 72, - 86, 90, 88, 92, 103, 77, 79, 83, 78, 81, - 80, 82, 13, 12, 15, 14, 17, 18, 19, 16, - 2, 1, 0, 4, 6, 7, 9, 8, 33, 32, - 31, 30, 29, 27, 25, 28, 26, 23, 21, 20, - 24, 22, 5, 3, 10, 11, 106, 87, 91, 104, - 97, 100, -}; - -static unsigned const ncore_pins[BYT_NGPIO_NCORE] = { - 19, 18, 17, 20, 21, 22, 24, 25, 23, 16, - 14, 15, 12, 26, 27, 1, 4, 8, 11, 0, - 3, 6, 10, 13, 2, 5, 9, 7, -}; - -static unsigned const sus_pins[BYT_NGPIO_SUS] = { - 29, 33, 30, 31, 32, 34, 36, 35, 38, 37, - 18, 7, 11, 20, 17, 1, 8, 10, 19, 12, - 0, 2, 23, 39, 28, 27, 22, 21, 24, 25, - 26, 51, 56, 54, 49, 55, 48, 57, 50, 58, - 52, 53, 59, 40, -}; - -static struct pinctrl_gpio_range byt_ranges[] = { - { - .name = BYT_SCORE_ACPI_UID, /* match with acpi _UID in probe */ - .npins = BYT_NGPIO_SCORE, - .pins = score_pins, - }, - { - .name = BYT_NCORE_ACPI_UID, - .npins = BYT_NGPIO_NCORE, - .pins = ncore_pins, - }, - { - .name = BYT_SUS_ACPI_UID, - .npins = BYT_NGPIO_SUS, - .pins = sus_pins, - }, - { - }, -}; - -struct byt_gpio { - struct gpio_chip chip; - struct platform_device *pdev; - spinlock_t lock; - void __iomem *reg_base; - struct pinctrl_gpio_range *range; -}; - -#define to_byt_gpio(c) container_of(c, struct byt_gpio, chip) - -static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset, - int reg) -{ - struct byt_gpio *vg = to_byt_gpio(chip); - u32 reg_offset; - - if (reg == BYT_INT_STAT_REG) - reg_offset = (offset / 32) * 4; - else - reg_offset = vg->range->pins[offset] * 16; - - return vg->reg_base + reg_offset + reg; -} - -static bool is_special_pin(struct byt_gpio *vg, unsigned offset) -{ - /* SCORE pin 92-93 */ - if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) && - offset >= 92 && offset <= 93) - return true; - - /* SUS pin 11-21 */ - if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) && - offset >= 11 && offset <= 21) - return true; - - return false; -} - -static int byt_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - struct byt_gpio *vg = to_byt_gpio(chip); - void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG); - u32 value; - bool special; - - /* - * In most cases, func pin mux 000 means GPIO function. - * But, some pins may have func pin mux 001 represents - * GPIO function. Only allow user to export pin with - * func pin mux preset as GPIO function by BIOS/FW. - */ - value = readl(reg) & BYT_PIN_MUX; - special = is_special_pin(vg, offset); - if ((special && value != 1) || (!special && value)) { - dev_err(&vg->pdev->dev, - "pin %u cannot be used as GPIO.\n", offset); - return -EINVAL; - } - - pm_runtime_get(&vg->pdev->dev); - - return 0; -} - -static void byt_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - struct byt_gpio *vg = to_byt_gpio(chip); - void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); - u32 value; - - /* clear interrupt triggering */ - value = readl(reg); - value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); - writel(value, reg); - - pm_runtime_put(&vg->pdev->dev); -} - -static int byt_irq_type(struct irq_data *d, unsigned type) -{ - struct byt_gpio *vg = to_byt_gpio(irq_data_get_irq_chip_data(d)); - u32 offset = irqd_to_hwirq(d); - u32 value; - unsigned long flags; - void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); - - if (offset >= vg->chip.ngpio) - return -EINVAL; - - spin_lock_irqsave(&vg->lock, flags); - value = readl(reg); - - /* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits - * are used to indicate high and low level triggering - */ - value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); - - switch (type) { - case IRQ_TYPE_LEVEL_HIGH: - value |= BYT_TRIG_LVL; - case IRQ_TYPE_EDGE_RISING: - value |= BYT_TRIG_POS; - break; - case IRQ_TYPE_LEVEL_LOW: - value |= BYT_TRIG_LVL; - case IRQ_TYPE_EDGE_FALLING: - value |= BYT_TRIG_NEG; - break; - case IRQ_TYPE_EDGE_BOTH: - value |= (BYT_TRIG_NEG | BYT_TRIG_POS); - break; - } - writel(value, reg); - - spin_unlock_irqrestore(&vg->lock, flags); - - return 0; -} - -static int byt_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); - return readl(reg) & BYT_LEVEL; -} - -static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct byt_gpio *vg = to_byt_gpio(chip); - void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); - unsigned long flags; - u32 old_val; - - spin_lock_irqsave(&vg->lock, flags); - - old_val = readl(reg); - - if (value) - writel(old_val | BYT_LEVEL, reg); - else - writel(old_val & ~BYT_LEVEL, reg); - - spin_unlock_irqrestore(&vg->lock, flags); -} - -static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct byt_gpio *vg = to_byt_gpio(chip); - void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); - unsigned long flags; - u32 value; - - spin_lock_irqsave(&vg->lock, flags); - - value = readl(reg) | BYT_DIR_MASK; - value &= ~BYT_INPUT_EN; /* active low */ - writel(value, reg); - - spin_unlock_irqrestore(&vg->lock, flags); - - return 0; -} - -static int byt_gpio_direction_output(struct gpio_chip *chip, - unsigned gpio, int value) -{ - struct byt_gpio *vg = to_byt_gpio(chip); - void __iomem *conf_reg = byt_gpio_reg(chip, gpio, BYT_CONF0_REG); - void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG); - unsigned long flags; - u32 reg_val; - - spin_lock_irqsave(&vg->lock, flags); - - /* - * Before making any direction modifications, do a check if gpio - * is set for direct IRQ. On baytrail, setting GPIO to output does - * not make sense, so let's at least warn the caller before they shoot - * themselves in the foot. - */ - WARN(readl(conf_reg) & BYT_DIRECT_IRQ_EN, - "Potential Error: Setting GPIO with direct_irq_en to output"); - - reg_val = readl(reg) | BYT_DIR_MASK; - reg_val &= ~BYT_OUTPUT_EN; - - if (value) - writel(reg_val | BYT_LEVEL, reg); - else - writel(reg_val & ~BYT_LEVEL, reg); - - spin_unlock_irqrestore(&vg->lock, flags); - - return 0; -} - -static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) -{ - struct byt_gpio *vg = to_byt_gpio(chip); - int i; - unsigned long flags; - u32 conf0, val, offs; - - spin_lock_irqsave(&vg->lock, flags); - - for (i = 0; i < vg->chip.ngpio; i++) { - const char *pull_str = NULL; - const char *pull = NULL; - const char *label; - offs = vg->range->pins[i] * 16; - conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG); - val = readl(vg->reg_base + offs + BYT_VAL_REG); - - label = gpiochip_is_requested(chip, i); - if (!label) - label = "Unrequested"; - - switch (conf0 & BYT_PULL_ASSIGN_MASK) { - case BYT_PULL_ASSIGN_UP: - pull = "up"; - break; - case BYT_PULL_ASSIGN_DOWN: - pull = "down"; - break; - } - - switch (conf0 & BYT_PULL_STR_MASK) { - case BYT_PULL_STR_2K: - pull_str = "2k"; - break; - case BYT_PULL_STR_10K: - pull_str = "10k"; - break; - case BYT_PULL_STR_20K: - pull_str = "20k"; - break; - case BYT_PULL_STR_40K: - pull_str = "40k"; - break; - } - - seq_printf(s, - " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s", - i, - label, - val & BYT_INPUT_EN ? " " : "in", - val & BYT_OUTPUT_EN ? " " : "out", - val & BYT_LEVEL ? "hi" : "lo", - vg->range->pins[i], offs, - conf0 & 0x7, - conf0 & BYT_TRIG_NEG ? " fall" : " ", - conf0 & BYT_TRIG_POS ? " rise" : " ", - conf0 & BYT_TRIG_LVL ? " level" : " "); - - if (pull && pull_str) - seq_printf(s, " %-4s %-3s", pull, pull_str); - else - seq_puts(s, " "); - - if (conf0 & BYT_IODEN) - seq_puts(s, " open-drain"); - - seq_puts(s, "\n"); - } - spin_unlock_irqrestore(&vg->lock, flags); -} - -static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc)); - struct irq_chip *chip = irq_data_get_irq_chip(data); - u32 base, pin, mask; - void __iomem *reg; - u32 pending; - unsigned virq; - int looplimit = 0; - - /* check from GPIO controller which pin triggered the interrupt */ - for (base = 0; base < vg->chip.ngpio; base += 32) { - - reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG); - - while ((pending = readl(reg))) { - pin = __ffs(pending); - mask = BIT(pin); - /* Clear before handling so we can't lose an edge */ - writel(mask, reg); - - virq = irq_find_mapping(vg->chip.irqdomain, base + pin); - generic_handle_irq(virq); - - /* In case bios or user sets triggering incorretly a pin - * might remain in "interrupt triggered" state. - */ - if (looplimit++ > 32) { - dev_err(&vg->pdev->dev, - "Gpio %d interrupt flood, disabling\n", - base + pin); - - reg = byt_gpio_reg(&vg->chip, base + pin, - BYT_CONF0_REG); - mask = readl(reg); - mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS | - BYT_TRIG_LVL); - writel(mask, reg); - mask = readl(reg); /* flush */ - break; - } - } - } - chip->irq_eoi(data); -} - -static void byt_irq_unmask(struct irq_data *d) -{ -} - -static void byt_irq_mask(struct irq_data *d) -{ -} - -static struct irq_chip byt_irqchip = { - .name = "BYT-GPIO", - .irq_mask = byt_irq_mask, - .irq_unmask = byt_irq_unmask, - .irq_set_type = byt_irq_type, - .flags = IRQCHIP_SKIP_SET_WAKE, -}; - -static void byt_gpio_irq_init_hw(struct byt_gpio *vg) -{ - void __iomem *reg; - u32 base, value; - - /* clear interrupt status trigger registers */ - for (base = 0; base < vg->chip.ngpio; base += 32) { - reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG); - writel(0xffffffff, reg); - /* make sure trigger bits are cleared, if not then a pin - might be misconfigured in bios */ - value = readl(reg); - if (value) - dev_err(&vg->pdev->dev, - "GPIO interrupt error, pins misconfigured\n"); - } -} - -static int byt_gpio_probe(struct platform_device *pdev) -{ - struct byt_gpio *vg; - struct gpio_chip *gc; - struct resource *mem_rc, *irq_rc; - struct device *dev = &pdev->dev; - struct acpi_device *acpi_dev; - struct pinctrl_gpio_range *range; - acpi_handle handle = ACPI_HANDLE(dev); - int ret; - - if (acpi_bus_get_device(handle, &acpi_dev)) - return -ENODEV; - - vg = devm_kzalloc(dev, sizeof(struct byt_gpio), GFP_KERNEL); - if (!vg) { - dev_err(&pdev->dev, "can't allocate byt_gpio chip data\n"); - return -ENOMEM; - } - - for (range = byt_ranges; range->name; range++) { - if (!strcmp(acpi_dev->pnp.unique_id, range->name)) { - vg->chip.ngpio = range->npins; - vg->range = range; - break; - } - } - - if (!vg->chip.ngpio || !vg->range) - return -ENODEV; - - vg->pdev = pdev; - platform_set_drvdata(pdev, vg); - - mem_rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); - vg->reg_base = devm_ioremap_resource(dev, mem_rc); - if (IS_ERR(vg->reg_base)) - return PTR_ERR(vg->reg_base); - - spin_lock_init(&vg->lock); - - gc = &vg->chip; - gc->label = dev_name(&pdev->dev); - gc->owner = THIS_MODULE; - gc->request = byt_gpio_request; - gc->free = byt_gpio_free; - gc->direction_input = byt_gpio_direction_input; - gc->direction_output = byt_gpio_direction_output; - gc->get = byt_gpio_get; - gc->set = byt_gpio_set; - gc->dbg_show = byt_gpio_dbg_show; - gc->base = -1; - gc->can_sleep = false; - gc->dev = dev; - - ret = gpiochip_add(gc); - if (ret) { - dev_err(&pdev->dev, "failed adding byt-gpio chip\n"); - return ret; - } - - /* set up interrupts */ - irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (irq_rc && irq_rc->start) { - byt_gpio_irq_init_hw(vg); - ret = gpiochip_irqchip_add(gc, &byt_irqchip, 0, - handle_simple_irq, IRQ_TYPE_NONE); - if (ret) { - dev_err(dev, "failed to add irqchip\n"); - gpiochip_remove(gc); - return ret; - } - - gpiochip_set_chained_irqchip(gc, &byt_irqchip, - (unsigned)irq_rc->start, - byt_gpio_irq_handler); - } - - pm_runtime_enable(dev); - - return 0; -} - -static int byt_gpio_runtime_suspend(struct device *dev) -{ - return 0; -} - -static int byt_gpio_runtime_resume(struct device *dev) -{ - return 0; -} - -static const struct dev_pm_ops byt_gpio_pm_ops = { - .runtime_suspend = byt_gpio_runtime_suspend, - .runtime_resume = byt_gpio_runtime_resume, -}; - -static const struct acpi_device_id byt_gpio_acpi_match[] = { - { "INT33B2", 0 }, - { "INT33FC", 0 }, - { } -}; -MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match); - -static int byt_gpio_remove(struct platform_device *pdev) -{ - struct byt_gpio *vg = platform_get_drvdata(pdev); - - pm_runtime_disable(&pdev->dev); - gpiochip_remove(&vg->chip); - - return 0; -} - -static struct platform_driver byt_gpio_driver = { - .probe = byt_gpio_probe, - .remove = byt_gpio_remove, - .driver = { - .name = "byt_gpio", - .owner = THIS_MODULE, - .pm = &byt_gpio_pm_ops, - .acpi_match_table = ACPI_PTR(byt_gpio_acpi_match), - }, -}; - -static int __init byt_gpio_init(void) -{ - return platform_driver_register(&byt_gpio_driver); -} -subsys_initcall(byt_gpio_init); - -static void __exit byt_gpio_exit(void) -{ - platform_driver_unregister(&byt_gpio_driver); -} -module_exit(byt_gpio_exit); -- cgit v1.1 From 876d716ba9af205f46b7e911d39482e627aea0e8 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 21 Oct 2014 10:47:32 -0700 Subject: pinctrl: rockchip: Set wake_enabled The rockchip pinctrl driver uses irq_gc_set_wake() but doesn't setup the .wake_enabled member. That means that we can never actually use a pin for wakeup. When "irq_set_irq_wake()" tries to call through it will always get a failure from set_irq_wake_real() and will then set wake_depth to 0. Assuming you can resume you'll later get an error message about "Unbalanced IRQ x wake disable". Signed-off-by: Doug Anderson Tested-by: Chris Zhong Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 016f457..230d8f3 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1563,6 +1563,7 @@ static int rockchip_interrupts_register(struct platform_device *pdev, gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type; + gc->wake_enabled = IRQ_MSK(bank->nr_pins); irq_set_handler_data(bank->irq, bank); irq_set_chained_handler(bank->irq, rockchip_irq_demux); -- cgit v1.1 From e5c2c9db0a2cff4d4df4b94f91146b26a0f0adc7 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 21 Oct 2014 10:47:33 -0700 Subject: pinctrl: rockchip: Don't call pinctrl_gpio_direction_output() in pin_config_set() The Rockchip pinctrl driver was calling rockchip_gpio_direction_output() in the pin_config_set() callback. This was just a shortcut for: * rockchip_gpio_set() * pinctrl_gpio_direction_output() Unfortunately it's not so good to call pinctrl_gpio_direction_output() from pin_config_set(). Specifically when initting hogs you'll get an error. Let's refactor a little so we can call _rockchip_pmx_gpio_set_direction() directly. Signed-off-by: Doug Anderson Tested-by: Chris Zhong Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 41 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 230d8f3..8a3c582 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -856,22 +856,14 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, * leads to this function call (via the pinctrl_gpio_direction_{input|output}() * function called from the gpiolib interface). */ -static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned offset, bool input) +static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip, + int pin, bool input) { - struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct rockchip_pin_bank *bank; - struct gpio_chip *chip; - int pin, ret; + int ret; u32 data; - chip = range->gc; bank = gc_to_pin_bank(chip); - pin = offset - chip->base; - - dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n", - offset, range->name, pin, input ? "input" : "output"); ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO); if (ret < 0) @@ -888,6 +880,23 @@ static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, return 0; } +static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset, bool input) +{ + struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct gpio_chip *chip; + int pin; + + chip = range->gc; + pin = offset - chip->base; + dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n", + offset, range->name, pin, input ? "input" : "output"); + + return _rockchip_pmx_gpio_set_direction(chip, offset - chip->base, + input); +} + static const struct pinmux_ops rockchip_pmx_ops = { .get_functions_count = rockchip_pmx_get_funcs_count, .get_function_name = rockchip_pmx_get_func_name, @@ -917,8 +926,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, return false; } -static int rockchip_gpio_direction_output(struct gpio_chip *gc, - unsigned offset, int value); +static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value); static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset); /* set the pin config settings for a specified pin */ @@ -959,9 +967,10 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, return rc; break; case PIN_CONFIG_OUTPUT: - rc = rockchip_gpio_direction_output(&bank->gpio_chip, - pin - bank->pin_base, - arg); + rockchip_gpio_set(&bank->gpio_chip, + pin - bank->pin_base, arg); + rc = _rockchip_pmx_gpio_set_direction(&bank->gpio_chip, + pin - bank->pin_base, false); if (rc) return rc; break; -- cgit v1.1 From 0fb7dcb1b3328e2ec4958b681f2e31dfd8f004fb Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 21 Oct 2014 10:47:34 -0700 Subject: pinctrl: rockchip: Parse pin groups before calling pinctrl_register() Just like in (529301c pinctrl: samsung: Parse pin groups before calling pinctrl_register()), Rockchip also needs to parse pin groups earlier to make hogs work. Signed-off-by: Doug Anderson Tested-by: Chris Zhong Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 8a3c582..6c14f6c 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1262,6 +1262,10 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, } } + ret = rockchip_pinctrl_parse_dt(pdev, info); + if (ret) + return ret; + info->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, info); if (!info->pctl_dev) { dev_err(&pdev->dev, "could not register pinctrl driver\n"); @@ -1279,12 +1283,6 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange); } - ret = rockchip_pinctrl_parse_dt(pdev, info); - if (ret) { - pinctrl_unregister(info->pctl_dev); - return ret; - } - return 0; } -- cgit v1.1 From fab262f5000407ce86a010ab5bc683c01c02d1a6 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 21 Oct 2014 10:47:35 -0700 Subject: pinctrl: rockchip: Protect read-modify-write with the spinlock There were a few instances where the rockchip pinctrl driver would do read-modify-write with no spinlock. Add a spinlock for these cases. Signed-off-by: Doug Anderson Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 6c14f6c..59a5461 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -861,6 +861,7 @@ static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip, { struct rockchip_pin_bank *bank; int ret; + unsigned long flags; u32 data; bank = gc_to_pin_bank(chip); @@ -869,6 +870,8 @@ static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip, if (ret < 0) return ret; + spin_lock_irqsave(&bank->slock, flags); + data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); /* set bit to 1 for output, 0 for input */ if (!input) @@ -877,6 +880,8 @@ static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip, data &= ~BIT(pin); writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); + spin_unlock_irqrestore(&bank->slock, flags); + return 0; } @@ -1394,6 +1399,7 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) u32 polarity = 0, data = 0; u32 pend; bool edge_changed = false; + unsigned long flags; dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name); @@ -1439,10 +1445,14 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) if (bank->toggle_edge_mode && edge_changed) { /* Interrupt params should only be set with ints disabled */ + spin_lock_irqsave(&bank->slock, flags); + data = readl_relaxed(bank->reg_base + GPIO_INTEN); writel_relaxed(0, bank->reg_base + GPIO_INTEN); writel(polarity, bank->reg_base + GPIO_INT_POLARITY); writel(data, bank->reg_base + GPIO_INTEN); + + spin_unlock_irqrestore(&bank->slock, flags); } chained_irq_exit(chip, desc); @@ -1456,6 +1466,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) u32 polarity; u32 level; u32 data; + unsigned long flags; int ret; /* make sure the pin is configured as gpio input */ @@ -1463,15 +1474,20 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) if (ret < 0) return ret; + spin_lock_irqsave(&bank->slock, flags); + data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); data &= ~mask; writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); + spin_unlock_irqrestore(&bank->slock, flags); + if (type & IRQ_TYPE_EDGE_BOTH) __irq_set_handler_locked(d->irq, handle_edge_irq); else __irq_set_handler_locked(d->irq, handle_level_irq); + spin_lock_irqsave(&bank->slock, flags); irq_gc_lock(gc); level = readl_relaxed(gc->reg_base + GPIO_INTTYPE_LEVEL); @@ -1514,6 +1530,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) break; default: irq_gc_unlock(gc); + spin_unlock_irqrestore(&bank->slock, flags); return -EINVAL; } @@ -1521,6 +1538,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY); irq_gc_unlock(gc); + spin_unlock_irqrestore(&bank->slock, flags); return 0; } -- cgit v1.1 From fdaaf6d6609b0ddb65cd3211cc7ceb892d7a2550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 21 Oct 2014 11:40:45 +0200 Subject: pinctrl: mxs: warn if functions are not grouped by name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mxs pinctrl driver cannot handle when functions are not grouped by name (which IMO is a bug). This happens for example if a imx28-somemachine.dts provides a function that has the same name as a function defined in imx28.dtsi. The proper way to fix that would be to check for duplicates in the loops (which increases parsing time) or parse the groups first and sort the resulting array. Signed-off-by: Uwe Kleine-König Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-mxs.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c index f98c6bb..646d5c2 100644 --- a/drivers/pinctrl/freescale/pinctrl-mxs.c +++ b/drivers/pinctrl/freescale/pinctrl-mxs.c @@ -445,6 +445,31 @@ static int mxs_pinctrl_probe_dt(struct platform_device *pdev, if (of_property_read_u32(child, "reg", &val)) continue; if (strcmp(fn, child->name)) { + struct device_node *child2; + + /* + * This reference is dropped by + * of_get_next_child(np, * child) + */ + of_node_get(child); + + /* + * The logic parsing the functions from dt currently + * doesn't handle if functions with the same name are + * not grouped together. Only the first contiguous + * cluster is usable for each function name. This is a + * bug that is not trivial to fix, but at least warn + * about it. + */ + for (child2 = of_get_next_child(np, child); + child2 != NULL; + child2 = of_get_next_child(np, child2)) { + if (!strcmp(child2->name, fn)) + dev_warn(&pdev->dev, + "function nodes must be grouped by name (failed for: %s)", + fn); + } + f = &soc->functions[idxf++]; f->name = fn = child->name; } -- cgit v1.1 From 4f6bd5cfc6c8f2e8c2c38fdfea8e32f9a463cdbb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 28 Oct 2014 22:41:26 +0100 Subject: pinctrl: sunxi: Add PN bank base pin The A80 R-PIO controller has one more bank that what we've seen so far, add the PN pin bank. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index 4245b96..5a51523 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -27,6 +27,7 @@ #define PI_BASE 256 #define PL_BASE 352 #define PM_BASE 384 +#define PN_BASE 416 #define SUNXI_PINCTRL_PIN(bank, pin) \ PINCTRL_PIN(P ## bank ## _BASE + (pin), "P" #bank #pin) -- cgit v1.1 From d5e9fb31baa2b1fd6d2043c748e6ff9313dfa8b5 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 28 Oct 2014 22:41:27 +0100 Subject: pinctrl: sunxi: Add A80 pinctrl muxing options The A80 has a rather usual pin controller, the only thing out of the ordinary being that it has 5 interrupts banks, and that some pins have several options for the same functions. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/Kconfig | 4 + drivers/pinctrl/sunxi/Makefile | 1 + drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c | 749 ++++++++++++++++++++++++++++++ 3 files changed, 754 insertions(+) create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index a5e10f7..230a952 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -39,4 +39,8 @@ config PINCTRL_SUN8I_A23_R depends on RESET_CONTROLLER select PINCTRL_SUNXI_COMMON +config PINCTRL_SUN9I_A80 + def_bool MACH_SUN9I + select PINCTRL_SUNXI_COMMON + endif diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile index e797efb..c7d92e4 100644 --- a/drivers/pinctrl/sunxi/Makefile +++ b/drivers/pinctrl/sunxi/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_PINCTRL_SUN6I_A31_R) += pinctrl-sun6i-a31-r.o obj-$(CONFIG_PINCTRL_SUN7I_A20) += pinctrl-sun7i-a20.o obj-$(CONFIG_PINCTRL_SUN8I_A23) += pinctrl-sun8i-a23.o obj-$(CONFIG_PINCTRL_SUN8I_A23_R) += pinctrl-sun8i-a23-r.o +obj-$(CONFIG_PINCTRL_SUN9I_A80) += pinctrl-sun9i-a80.o diff --git a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c new file mode 100644 index 0000000..adb2942 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c @@ -0,0 +1,749 @@ +/* + * Allwinner A80 SoCs pinctrl driver. + * + * Copyright (C) 2014 Maxime Ripard + * + * Maxime Ripard + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#include "pinctrl-sunxi.h" + +static const struct sunxi_desc_pin sun9i_a80_pins[] = { + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD3 */ + SUNXI_FUNCTION(0x4, "uart1"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* PA_EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD2 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* PA_EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD1 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* PA_EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD0 */ + SUNXI_FUNCTION(0x4, "uart1"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* PA_EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXCK */ + SUNXI_FUNCTION(0x4, "uart1"), /* DTR */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* PA_EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXCTL */ + SUNXI_FUNCTION(0x4, "uart1"), /* DSR */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* PA_EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXERR */ + SUNXI_FUNCTION(0x4, "uart1"), /* DCD */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* PA_EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD3 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RING */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* PA_EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD2 */ + SUNXI_FUNCTION(0x4, "eclk"), /* IN0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* PA_EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXEN */ + SUNXI_FUNCTION(0x4, "eclk"), /* IN1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* PA_EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD0 */ + SUNXI_FUNCTION(0x4, "clk_out_a"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* PA_EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* MII-CRS */ + SUNXI_FUNCTION(0x4, "clk_out_b"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* PA_EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXCK */ + SUNXI_FUNCTION(0x4, "pwm3"), /* PWM_P */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* PA_EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RGMII-TXCK / GMII-TXEN */ + SUNXI_FUNCTION(0x4, "pwm3"), /* PWM_N */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 13)), /* PA_EINT13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* MII-TXERR */ + SUNXI_FUNCTION(0x4, "spi1"), /* CS0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PA_EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RGMII-CLKIN / MII-COL */ + SUNXI_FUNCTION(0x4, "spi1"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PA_EINT15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* EMDC */ + SUNXI_FUNCTION(0x4, "spi1"), /* MOSI */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PA_EINT16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* EMDIO */ + SUNXI_FUNCTION(0x4, "spi1"), /* MISO */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */ + + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "uart3"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)), /* PB_EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "uart3"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)), /* PB_EINT6 */ + + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "mcsi"), /* MCLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PB_EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "mcsi"), /* SCK */ + SUNXI_FUNCTION(0x4, "i2c4"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PB_EINT15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "mcsi"), /* SDA */ + SUNXI_FUNCTION(0x4, "i2c4"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PB_EINT16 */ + + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* WE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* ALE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* CLE */ + SUNXI_FUNCTION(0x3, "spi0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* CE1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* CE0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* RE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* RB0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* RB1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ2 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ3 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ4 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ5 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ6 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ7 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQS */ + SUNXI_FUNCTION(0x3, "mmc2")), /* RST */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* CE2 */ + SUNXI_FUNCTION(0x3, "nand0_b")), /* RE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* CE3 */ + SUNXI_FUNCTION(0x3, "nand0_b")), /* DQS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ + + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D0 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D1 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VPC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D8 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D9 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VP0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VN0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VP1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VN1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VP2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VN2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D16 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VPC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D17 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VP3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */ + SUNXI_FUNCTION(0x3, "lvds1")), /* VN3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D20 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D21 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D22 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D23 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* DE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* HSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* VSYNC */ + + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* PCLK */ + SUNXI_FUNCTION(0x3, "ts"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)), /* PE_EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* MCLK */ + SUNXI_FUNCTION(0x3, "ts"), /* ERR */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)), /* PE_EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* HSYNC */ + SUNXI_FUNCTION(0x3, "ts"), /* SYNC */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)), /* PE_EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* VSYNC */ + SUNXI_FUNCTION(0x3, "ts"), /* DVLD */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)), /* PE_EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D0 */ + SUNXI_FUNCTION(0x3, "spi2"), /* CS0 */ + SUNXI_FUNCTION(0x4, "uart5"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)), /* PE_EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D1 */ + SUNXI_FUNCTION(0x3, "spi2"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart5"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)), /* PE_EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D2 */ + SUNXI_FUNCTION(0x3, "spi2"), /* MOSI */ + SUNXI_FUNCTION(0x4, "uart5"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)), /* PE_EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D3 */ + SUNXI_FUNCTION(0x3, "spi2"), /* MISO */ + SUNXI_FUNCTION(0x4, "uart5"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)), /* PE_EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D4 */ + SUNXI_FUNCTION(0x3, "ts"), /* D0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)), /* PE_EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D5 */ + SUNXI_FUNCTION(0x3, "ts"), /* D1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)), /* PE_EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D6 */ + SUNXI_FUNCTION(0x3, "ts"), /* D2 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)), /* PE_EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D7 */ + SUNXI_FUNCTION(0x3, "ts"), /* D3 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)), /* PE_EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D8 */ + SUNXI_FUNCTION(0x3, "ts"), /* D4 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 12)), /* PE_EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D9 */ + SUNXI_FUNCTION(0x3, "ts"), /* D5 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 13)), /* PE_EINT13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D10 */ + SUNXI_FUNCTION(0x3, "ts"), /* D6 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 14)), /* PE_EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D11 */ + SUNXI_FUNCTION(0x3, "ts"), /* D7 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 15)), /* PE_EINT15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* SCK */ + SUNXI_FUNCTION(0x3, "i2c4"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 16)), /* PE_EINT16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* SDA */ + SUNXI_FUNCTION(0x3, "i2c4"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 17)), /* PE_EINT17 */ + + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart0")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ + SUNXI_FUNCTION(0x4, "uart0")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0")), /* D2 */ + + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 0)), /* PG_EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 1)), /* PG_EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 2)), /* PG_EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 3)), /* PG_EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 4)), /* PG_EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 5)), /* PG_EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 6)), /* PG_EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 7)), /* PG_EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 8)), /* PG_EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 9)), /* PG_EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c3"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 10)), /* PG_EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c3"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 11)), /* PG_EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart4"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 12)), /* PG_EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart4"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 13)), /* PG_EINT13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart4"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 14)), /* PG_EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart4"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 15)), /* PG_EINT15 */ + + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm0")), + + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "pwm1"), /* Positive */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 8)), /* PH_EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "pwm1"), /* Negative */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 9)), /* PH_EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "pwm2"), /* Positive */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 10)), /* PH_EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "pwm2"), /* Negative */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 11)), /* PH_EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0"), /* TX */ + SUNXI_FUNCTION(0x3, "spi3"), /* CS2 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 12)), /* PH_EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0"), /* RX */ + SUNXI_FUNCTION(0x3, "spi3"), /* CS2 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 13)), /* PH_EINT13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi3"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 14)), /* PH_EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi3"), /* MOSI */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 15)), /* PH_EINT15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi3"), /* MISO */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 16)), /* PH_EINT16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi3"), /* CS0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 17)), /* PH_EINT17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi3"), /* CS1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 18)), /* PH_EINT18 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "hdmi")), /* SCL */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 20), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "hdmi")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 21), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "hdmi")), /* CEC */ +}; + +static const struct sunxi_pinctrl_desc sun9i_a80_pinctrl_data = { + .pins = sun9i_a80_pins, + .npins = ARRAY_SIZE(sun9i_a80_pins), + .irq_banks = 5, +}; + +static int sun9i_a80_pinctrl_probe(struct platform_device *pdev) +{ + return sunxi_pinctrl_init(pdev, + &sun9i_a80_pinctrl_data); +} + +static 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, + .driver = { + .name = "sun9i-a80-pinctrl", + .of_match_table = sun9i_a80_pinctrl_match, + }, +}; +module_platform_driver(sun9i_a80_pinctrl_driver); + +MODULE_AUTHOR("Maxime Ripard "); +MODULE_DESCRIPTION("Allwinner A80 pinctrl driver"); +MODULE_LICENSE("GPL"); -- cgit v1.1 From 0c49e2f668a50783519ed7de8f938ad12746cdc2 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 21 Oct 2014 14:36:58 +0530 Subject: pinctrl-bcm281xx: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-bcm281xx.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-bcm281xx.c b/drivers/pinctrl/pinctrl-bcm281xx.c index a26e0c2..2b25047 100644 --- a/drivers/pinctrl/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/pinctrl-bcm281xx.c @@ -1404,11 +1404,6 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) /* So far We can assume there is only 1 bank of registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Missing MEM resource\n"); - return -ENODEV; - } - pdata->reg_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pdata->reg_base)) { dev_err(&pdev->dev, "Failed to ioremap MEM resource\n"); -- cgit v1.1 From 9198f509c888f1ca8f5a50047d702b1ab29459a5 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Wed, 29 Oct 2014 19:51:59 +0800 Subject: pinctrl: rockchip: add suspend/resume functions support suspend/resume of pinctrl, it allows handling sleep mode for hogged pins in pinctrl Signed-off-by: Chris Zhong Tested-by: Doug Anderson Reviewed-by: Doug Anderson Tested-by: Heiko Stuebner Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 59a5461..28b1218 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1796,6 +1796,23 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( return ctrl; } +static int __maybe_unused rockchip_pinctrl_suspend(struct device *dev) +{ + struct rockchip_pinctrl *info = dev_get_drvdata(dev); + + return pinctrl_force_sleep(info->pctl_dev); +} + +static int __maybe_unused rockchip_pinctrl_resume(struct device *dev) +{ + struct rockchip_pinctrl *info = dev_get_drvdata(dev); + + return pinctrl_force_default(info->pctl_dev); +} + +static SIMPLE_DEV_PM_OPS(rockchip_pinctrl_dev_pm_ops, rockchip_pinctrl_suspend, + rockchip_pinctrl_resume); + static int rockchip_pinctrl_probe(struct platform_device *pdev) { struct rockchip_pinctrl *info; @@ -2009,6 +2026,7 @@ static struct platform_driver rockchip_pinctrl_driver = { .driver = { .name = "rockchip-pinctrl", .owner = THIS_MODULE, + .pm = &rockchip_pinctrl_dev_pm_ops, .of_match_table = rockchip_pinctrl_dt_match, }, }; -- cgit v1.1 From 8dca9331270240125fedbe83e0a2cd5750ed9fff Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Wed, 29 Oct 2014 19:52:00 +0800 Subject: pinctrl: rockchip: save and restore gpio6_c6 pinmux in suspend/resume Save and restore the gpio6_c6 pinmux setting, since Maskrom of RK3288 would modify it to sdmmc0_det, so it need to be restored to the correct setting after resume from Maskrom. Signed-off-by: Chris Zhong Tested-by: Doug Anderson Reviewed-by: Doug Anderson Tested-by: Heiko Stuebner Signed-off-by: Heiko Stuebner --- drivers/pinctrl/pinctrl-rockchip.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 28b1218..40970c3 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1796,16 +1796,44 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( return ctrl; } +#define RK3288_GRF_GPIO6C_IOMUX 0x64 +#define GPIO6C6_SEL_WRITE_ENABLE BIT(28) + +static u32 rk3288_grf_gpio6c_iomux; + static int __maybe_unused rockchip_pinctrl_suspend(struct device *dev) { struct rockchip_pinctrl *info = dev_get_drvdata(dev); + int ret = pinctrl_force_sleep(info->pctl_dev); + + if (ret) + return ret; + + /* + * RK3288 GPIO6_C6 mux would be modified by Maskrom when resume, so save + * the setting here, and restore it at resume. + */ + if (info->ctrl->type == RK3288) { + ret = regmap_read(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX, + &rk3288_grf_gpio6c_iomux); + if (ret) { + pinctrl_force_default(info->pctl_dev); + return ret; + } + } - return pinctrl_force_sleep(info->pctl_dev); + return 0; } static int __maybe_unused rockchip_pinctrl_resume(struct device *dev) { struct rockchip_pinctrl *info = dev_get_drvdata(dev); + int ret = regmap_write(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX, + rk3288_grf_gpio6c_iomux | + GPIO6C6_SEL_WRITE_ENABLE); + + if (ret) + return ret; return pinctrl_force_default(info->pctl_dev); } -- cgit v1.1 From 354567e6084c0760dc1e3a164ce4e77c5a943acc Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 3 Nov 2014 13:01:32 +0200 Subject: gpio / ACPI: Add knowledge about pin controllers to acpi_get_gpiod() The GPIO resources (GpioIo/GpioInt) used in ACPI contain a GPIO number which is relative to the hardware GPIO controller. Typically this number can be translated directly to Linux GPIO number because the mapping is pretty much 1:1. However, when the GPIO driver is using pins exported by a pin controller driver via set of GPIO ranges, the mapping might not be 1:1 anymore and direct translation does not work. In such cases we need to translate the ACPI GPIO number to be suitable for the GPIO controller driver in question by checking all the pin controller GPIO ranges under the given device and using those to get the proper GPIO number. Signed-off-by: Mika Westerberg Acked-by: Rafael J. Wysocki Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 62 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 05c6275..5be637d 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -11,12 +11,14 @@ */ #include +#include #include #include #include #include #include #include +#include #include "gpiolib.h" @@ -55,6 +57,58 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) return ACPI_HANDLE(gc->dev) == data; } +#ifdef CONFIG_PINCTRL +/** + * acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO + * @chip: GPIO chip + * @pin: ACPI GPIO pin number from GpioIo/GpioInt resource + * + * Function takes ACPI GpioIo/GpioInt pin number as a parameter and + * translates it to a corresponding offset suitable to be passed to a + * GPIO controller driver. + * + * Typically the returned offset is same as @pin, but if the GPIO + * controller uses pin controller and the mapping is not contigous the + * offset might be different. + */ +static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin) +{ + struct gpio_pin_range *pin_range; + + /* If there are no ranges in this chip, use 1:1 mapping */ + if (list_empty(&chip->pin_ranges)) + return pin; + + list_for_each_entry(pin_range, &chip->pin_ranges, node) { + const struct pinctrl_gpio_range *range = &pin_range->range; + int i; + + if (range->pins) { + for (i = 0; i < range->npins; i++) { + if (range->pins[i] == pin) + return range->base + i - chip->base; + } + } else { + if (pin >= range->pin_base && + pin < range->pin_base + range->npins) { + unsigned gpio_base; + + gpio_base = range->base - chip->base; + return gpio_base + pin - range->pin_base; + } + } + } + + return -EINVAL; +} +#else +static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, + int pin) +{ + return pin; +} +#endif + /** * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") @@ -69,6 +123,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) struct gpio_chip *chip; acpi_handle handle; acpi_status status; + int offset; status = acpi_get_handle(NULL, path, &handle); if (ACPI_FAILURE(status)) @@ -78,10 +133,11 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) if (!chip) return ERR_PTR(-ENODEV); - if (pin < 0 || pin > chip->ngpio) - return ERR_PTR(-EINVAL); + offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin); + if (offset < 0) + return ERR_PTR(offset); - return gpiochip_get_desc(chip, pin); + return gpiochip_get_desc(chip, offset); } static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) -- cgit v1.1 From 6e08d6bbebebcf70f982d7190c4b6dc456cedd57 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 3 Nov 2014 13:01:33 +0200 Subject: pinctrl: Add Intel Cherryview/Braswell pin controller support This driver supports the pin/GPIO controllers found in newer Intel SoCs like Cherryview and Braswell. The driver provides full GPIO support and minimal set of pin controlling funtionality. The driver is based on the original Cherryview GPIO driver authored by Ning Li and Alan Cox. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/Kconfig | 12 + drivers/pinctrl/intel/Makefile | 1 + drivers/pinctrl/intel/pinctrl-cherryview.c | 1519 ++++++++++++++++++++++++++++ 3 files changed, 1532 insertions(+) create mode 100644 drivers/pinctrl/intel/pinctrl-cherryview.c (limited to 'drivers') diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig index 957c903..b801d86 100644 --- a/drivers/pinctrl/intel/Kconfig +++ b/drivers/pinctrl/intel/Kconfig @@ -13,3 +13,15 @@ config PINCTRL_BAYTRAIL so only a small amount is available for gpio use. Requires ACPI device enumeration code to set up a platform device. + +config PINCTRL_CHERRYVIEW + tristate "Intel Cherryview/Braswell pinctrl and GPIO driver" + depends on ACPI + select PINMUX + select PINCONF + select GENERIC_PINCONF + select GPIOLIB + select GPIOLIB_IRQCHIP + help + Cherryview/Braswell pinctrl driver provides an interface that + allows configuring of SoC pins and using them as GPIOs. diff --git a/drivers/pinctrl/intel/Makefile b/drivers/pinctrl/intel/Makefile index d049b76..4c210e4 100644 --- a/drivers/pinctrl/intel/Makefile +++ b/drivers/pinctrl/intel/Makefile @@ -1,3 +1,4 @@ # Intel pin control drivers obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o +obj-$(CONFIG_PINCTRL_CHERRYVIEW) += pinctrl-cherryview.o diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c new file mode 100644 index 0000000..e9f8b39 --- /dev/null +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -0,0 +1,1519 @@ +/* + * Cherryview/Braswell pinctrl driver + * + * Copyright (C) 2014, Intel Corporation + * Author: Mika Westerberg + * + * This driver is based on the original Cherryview GPIO driver by + * Ning Li + * Alan Cox + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHV_INTSTAT 0x300 +#define CHV_INTMASK 0x380 + +#define FAMILY_PAD_REGS_OFF 0x4400 +#define FAMILY_PAD_REGS_SIZE 0x400 +#define MAX_FAMILY_PAD_GPIO_NO 15 +#define GPIO_REGS_SIZE 8 + +#define CHV_PADCTRL0 0x000 +#define CHV_PADCTRL0_INTSEL_SHIFT 28 +#define CHV_PADCTRL0_INTSEL_MASK (0xf << CHV_PADCTRL0_INTSEL_SHIFT) +#define CHV_PADCTRL0_TERM_UP BIT(23) +#define CHV_PADCTRL0_TERM_SHIFT 20 +#define CHV_PADCTRL0_TERM_MASK (7 << CHV_PADCTRL0_TERM_SHIFT) +#define CHV_PADCTRL0_TERM_20K 1 +#define CHV_PADCTRL0_TERM_5K 2 +#define CHV_PADCTRL0_TERM_1K 4 +#define CHV_PADCTRL0_PMODE_SHIFT 16 +#define CHV_PADCTRL0_PMODE_MASK (0xf << CHV_PADCTRL0_PMODE_SHIFT) +#define CHV_PADCTRL0_GPIOEN BIT(15) +#define CHV_PADCTRL0_GPIOCFG_SHIFT 8 +#define CHV_PADCTRL0_GPIOCFG_MASK (7 << CHV_PADCTRL0_GPIOCFG_SHIFT) +#define CHV_PADCTRL0_GPIOCFG_GPIO 0 +#define CHV_PADCTRL0_GPIOCFG_GPO 1 +#define CHV_PADCTRL0_GPIOCFG_GPI 2 +#define CHV_PADCTRL0_GPIOCFG_HIZ 3 +#define CHV_PADCTRL0_GPIOTXSTATE BIT(1) +#define CHV_PADCTRL0_GPIORXSTATE BIT(0) + +#define CHV_PADCTRL1 0x004 +#define CHV_PADCTRL1_CFGLOCK BIT(31) +#define CHV_PADCTRL1_INVRXTX_SHIFT 4 +#define CHV_PADCTRL1_INVRXTX_MASK (0xf << CHV_PADCTRL1_INVRXTX_SHIFT) +#define CHV_PADCTRL1_INVRXTX_TXENABLE (2 << CHV_PADCTRL1_INVRXTX_SHIFT) +#define CHV_PADCTRL1_ODEN BIT(3) +#define CHV_PADCTRL1_INVRXTX_RXDATA (4 << CHV_PADCTRL1_INVRXTX_SHIFT) +#define CHV_PADCTRL1_INTWAKECFG_MASK 7 +#define CHV_PADCTRL1_INTWAKECFG_FALLING 1 +#define CHV_PADCTRL1_INTWAKECFG_RISING 2 +#define CHV_PADCTRL1_INTWAKECFG_BOTH 3 +#define CHV_PADCTRL1_INTWAKECFG_LEVEL 4 + +/** + * struct chv_alternate_function - A per group or per pin alternate function + * @pin: Pin number (only used in per pin configs) + * @mode: Mode the pin should be set in + * @invert_oe: Invert OE for this pin + */ +struct chv_alternate_function { + unsigned pin; + u8 mode; + bool invert_oe; +}; + +/** + * struct chv_pincgroup - describes a CHV pin group + * @name: Name of the group + * @pins: An array of pins in this group + * @npins: Number of pins in this group + * @altfunc: Alternate function applied to all pins in this group + * @overrides: Alternate function override per pin or %NULL if not used + * @noverrides: Number of per pin alternate function overrides if + * @overrides != NULL. + */ +struct chv_pingroup { + const char *name; + const unsigned *pins; + size_t npins; + struct chv_alternate_function altfunc; + const struct chv_alternate_function *overrides; + size_t noverrides; +}; + +/** + * struct chv_function - A CHV pinmux function + * @name: Name of the function + * @groups: An array of groups for this function + * @ngroups: Number of groups in @groups + */ +struct chv_function { + const char *name; + const char * const *groups; + size_t ngroups; +}; + +/** + * struct chv_gpio_pinrange - A range of pins that can be used as GPIOs + * @base: Start pin number + * @npins: Number of pins in this range + */ +struct chv_gpio_pinrange { + unsigned base; + unsigned npins; +}; + +/** + * struct chv_community - A community specific configuration + * @uid: ACPI _UID used to match the community + * @pins: All pins in this community + * @npins: Number of pins + * @groups: All groups in this community + * @ngroups: Number of groups + * @functions: All functions in this community + * @nfunctions: Number of functions + * @ngpios: Number of GPIOs in this community + * @gpio_ranges: An array of GPIO ranges in this community + * @ngpio_ranges: Number of GPIO ranges + * @ngpios: Total number of GPIOs in this community + */ +struct chv_community { + const char *uid; + const struct pinctrl_pin_desc *pins; + size_t npins; + const struct chv_pingroup *groups; + size_t ngroups; + const struct chv_function *functions; + size_t nfunctions; + const struct chv_gpio_pinrange *gpio_ranges; + size_t ngpio_ranges; + size_t ngpios; +}; + +/** + * struct chv_pinctrl - CHV pinctrl private structure + * @dev: Pointer to the parent device + * @pctldesc: Pin controller description + * @pctldev: Pointer to the pin controller device + * @chip: GPIO chip in this pin controller + * @regs: MMIO registers + * @lock: Lock to serialize register accesses + * @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO + * offset (in GPIO number space) + * @community: Community this pinctrl instance represents + * + * The first group in @groups is expected to contain all pins that can be + * used as GPIOs. + */ +struct chv_pinctrl { + struct device *dev; + struct pinctrl_desc pctldesc; + struct pinctrl_dev *pctldev; + struct gpio_chip chip; + void __iomem *regs; + spinlock_t lock; + unsigned intr_lines[16]; + const struct chv_community *community; +}; + +#define gpiochip_to_pinctrl(c) container_of(c, struct chv_pinctrl, chip) + +#define ALTERNATE_FUNCTION(p, m, i) \ + { \ + .pin = (p), \ + .mode = (m), \ + .invert_oe = (i), \ + } + +#define PIN_GROUP(n, p, m, i) \ + { \ + .name = (n), \ + .pins = (p), \ + .npins = ARRAY_SIZE((p)), \ + .altfunc.mode = (m), \ + .altfunc.invert_oe = (i), \ + } + +#define PIN_GROUP_WITH_OVERRIDE(n, p, m, i, o) \ + { \ + .name = (n), \ + .pins = (p), \ + .npins = ARRAY_SIZE((p)), \ + .altfunc.mode = (m), \ + .altfunc.invert_oe = (i), \ + .overrides = (o), \ + .noverrides = ARRAY_SIZE((o)), \ + } + +#define FUNCTION(n, g) \ + { \ + .name = (n), \ + .groups = (g), \ + .ngroups = ARRAY_SIZE((g)), \ + } + +#define GPIO_PINRANGE(start, end) \ + { \ + .base = (start), \ + .npins = (end) - (start) + 1, \ + } + +static const struct pinctrl_pin_desc southwest_pins[] = { + PINCTRL_PIN(0, "FST_SPI_D2"), + PINCTRL_PIN(1, "FST_SPI_D0"), + PINCTRL_PIN(2, "FST_SPI_CLK"), + PINCTRL_PIN(3, "FST_SPI_D3"), + PINCTRL_PIN(4, "FST_SPI_CS1_B"), + PINCTRL_PIN(5, "FST_SPI_D1"), + PINCTRL_PIN(6, "FST_SPI_CS0_B"), + PINCTRL_PIN(7, "FST_SPI_CS2_B"), + + PINCTRL_PIN(15, "UART1_RTS_B"), + PINCTRL_PIN(16, "UART1_RXD"), + PINCTRL_PIN(17, "UART2_RXD"), + PINCTRL_PIN(18, "UART1_CTS_B"), + PINCTRL_PIN(19, "UART2_RTS_B"), + PINCTRL_PIN(20, "UART1_TXD"), + PINCTRL_PIN(21, "UART2_TXD"), + PINCTRL_PIN(22, "UART2_CTS_B"), + + PINCTRL_PIN(30, "MF_HDA_CLK"), + PINCTRL_PIN(31, "MF_HDA_RSTB"), + PINCTRL_PIN(32, "MF_HDA_SDIO"), + PINCTRL_PIN(33, "MF_HDA_SDO"), + PINCTRL_PIN(34, "MF_HDA_DOCKRSTB"), + PINCTRL_PIN(35, "MF_HDA_SYNC"), + PINCTRL_PIN(36, "MF_HDA_SDI1"), + PINCTRL_PIN(37, "MF_HDA_DOCKENB"), + + PINCTRL_PIN(45, "I2C5_SDA"), + PINCTRL_PIN(46, "I2C4_SDA"), + PINCTRL_PIN(47, "I2C6_SDA"), + PINCTRL_PIN(48, "I2C5_SCL"), + PINCTRL_PIN(49, "I2C_NFC_SDA"), + PINCTRL_PIN(50, "I2C4_SCL"), + PINCTRL_PIN(51, "I2C6_SCL"), + PINCTRL_PIN(52, "I2C_NFC_SCL"), + + PINCTRL_PIN(60, "I2C1_SDA"), + PINCTRL_PIN(61, "I2C0_SDA"), + PINCTRL_PIN(62, "I2C2_SDA"), + PINCTRL_PIN(63, "I2C1_SCL"), + PINCTRL_PIN(64, "I2C3_SDA"), + PINCTRL_PIN(65, "I2C0_SCL"), + PINCTRL_PIN(66, "I2C2_SCL"), + PINCTRL_PIN(67, "I2C3_SCL"), + + PINCTRL_PIN(75, "SATA_GP0"), + PINCTRL_PIN(76, "SATA_GP1"), + PINCTRL_PIN(77, "SATA_LEDN"), + PINCTRL_PIN(78, "SATA_GP2"), + PINCTRL_PIN(79, "MF_SMB_ALERTB"), + PINCTRL_PIN(80, "SATA_GP3"), + PINCTRL_PIN(81, "MF_SMB_CLK"), + PINCTRL_PIN(82, "MF_SMB_DATA"), + + PINCTRL_PIN(90, "PCIE_CLKREQ0B"), + PINCTRL_PIN(91, "PCIE_CLKREQ1B"), + PINCTRL_PIN(92, "GP_SSP_2_CLK"), + PINCTRL_PIN(93, "PCIE_CLKREQ2B"), + PINCTRL_PIN(94, "GP_SSP_2_RXD"), + PINCTRL_PIN(95, "PCIE_CLKREQ3B"), + PINCTRL_PIN(96, "GP_SSP_2_FS"), + PINCTRL_PIN(97, "GP_SSP_2_TXD"), +}; + +static const unsigned southwest_fspi_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; +static const unsigned southwest_uart0_pins[] = { 16, 20 }; +static const unsigned southwest_uart1_pins[] = { 15, 16, 18, 20 }; +static const unsigned southwest_uart2_pins[] = { 17, 19, 21, 22 }; +static const unsigned southwest_i2c0_pins[] = { 61, 65 }; +static const unsigned southwest_hda_pins[] = { 30, 31, 32, 33, 34, 35, 36, 37 }; +static const unsigned southwest_lpe_pins[] = { + 30, 31, 32, 33, 34, 35, 36, 37, 92, 94, 96, 97, +}; +static const unsigned southwest_i2c1_pins[] = { 60, 63 }; +static const unsigned southwest_i2c2_pins[] = { 62, 66 }; +static const unsigned southwest_i2c3_pins[] = { 64, 67 }; +static const unsigned southwest_i2c4_pins[] = { 46, 50 }; +static const unsigned southwest_i2c5_pins[] = { 45, 48 }; +static const unsigned southwest_i2c6_pins[] = { 47, 51 }; +static const unsigned southwest_i2c_nfc_pins[] = { 49, 52 }; +static const unsigned southwest_smbus_pins[] = { 79, 81, 82 }; +static const unsigned southwest_spi3_pins[] = { 76, 79, 80, 81, 82 }; + +/* LPE I2S TXD pins need to have invert_oe set */ +static const struct chv_alternate_function southwest_lpe_altfuncs[] = { + ALTERNATE_FUNCTION(30, 1, true), + ALTERNATE_FUNCTION(34, 1, true), + ALTERNATE_FUNCTION(97, 1, true), +}; + +/* + * Two spi3 chipselects are available in different mode than the main spi3 + * functionality, which is using mode 1. + */ +static const struct chv_alternate_function southwest_spi3_altfuncs[] = { + ALTERNATE_FUNCTION(76, 3, false), + ALTERNATE_FUNCTION(80, 3, false), +}; + +static const struct chv_pingroup southwest_groups[] = { + PIN_GROUP("uart0_grp", southwest_uart0_pins, 2, false), + PIN_GROUP("uart1_grp", southwest_uart1_pins, 1, false), + PIN_GROUP("uart2_grp", southwest_uart2_pins, 1, false), + PIN_GROUP("hda_grp", southwest_hda_pins, 2, false), + PIN_GROUP("i2c0_grp", southwest_i2c0_pins, 1, true), + PIN_GROUP("i2c1_grp", southwest_i2c1_pins, 1, true), + PIN_GROUP("i2c2_grp", southwest_i2c2_pins, 1, true), + PIN_GROUP("i2c3_grp", southwest_i2c3_pins, 1, true), + PIN_GROUP("i2c4_grp", southwest_i2c4_pins, 1, true), + PIN_GROUP("i2c5_grp", southwest_i2c5_pins, 1, true), + PIN_GROUP("i2c6_grp", southwest_i2c6_pins, 1, true), + PIN_GROUP("i2c_nfc_grp", southwest_i2c_nfc_pins, 2, true), + + PIN_GROUP_WITH_OVERRIDE("lpe_grp", southwest_lpe_pins, 1, false, + southwest_lpe_altfuncs), + PIN_GROUP_WITH_OVERRIDE("spi3_grp", southwest_spi3_pins, 2, false, + southwest_spi3_altfuncs), +}; + +static const char * const southwest_uart0_groups[] = { "uart0_grp" }; +static const char * const southwest_uart1_groups[] = { "uart1_grp" }; +static const char * const southwest_uart2_groups[] = { "uart2_grp" }; +static const char * const southwest_hda_groups[] = { "hda_grp" }; +static const char * const southwest_lpe_groups[] = { "lpe_grp" }; +static const char * const southwest_i2c0_groups[] = { "i2c0_grp" }; +static const char * const southwest_i2c1_groups[] = { "i2c1_grp" }; +static const char * const southwest_i2c2_groups[] = { "i2c2_grp" }; +static const char * const southwest_i2c3_groups[] = { "i2c3_grp" }; +static const char * const southwest_i2c4_groups[] = { "i2c4_grp" }; +static const char * const southwest_i2c5_groups[] = { "i2c5_grp" }; +static const char * const southwest_i2c6_groups[] = { "i2c6_grp" }; +static const char * const southwest_i2c_nfc_groups[] = { "i2c_nfc_grp" }; +static const char * const southwest_spi3_groups[] = { "spi3_grp" }; + +/* + * Only do pinmuxing for certain LPSS devices for now. Rest of the pins are + * enabled only as GPIOs. + */ +static const struct chv_function southwest_functions[] = { + FUNCTION("uart0", southwest_uart0_groups), + FUNCTION("uart1", southwest_uart1_groups), + FUNCTION("uart2", southwest_uart2_groups), + FUNCTION("hda", southwest_hda_groups), + FUNCTION("lpe", southwest_lpe_groups), + FUNCTION("i2c0", southwest_i2c0_groups), + FUNCTION("i2c1", southwest_i2c1_groups), + FUNCTION("i2c2", southwest_i2c2_groups), + FUNCTION("i2c3", southwest_i2c3_groups), + FUNCTION("i2c4", southwest_i2c4_groups), + FUNCTION("i2c5", southwest_i2c5_groups), + FUNCTION("i2c6", southwest_i2c6_groups), + FUNCTION("i2c_nfc", southwest_i2c_nfc_groups), + FUNCTION("spi3", southwest_spi3_groups), +}; + +static const struct chv_gpio_pinrange southwest_gpio_ranges[] = { + GPIO_PINRANGE(0, 7), + GPIO_PINRANGE(15, 22), + GPIO_PINRANGE(30, 37), + GPIO_PINRANGE(45, 52), + GPIO_PINRANGE(60, 67), + GPIO_PINRANGE(75, 82), + GPIO_PINRANGE(90, 97), +}; + +static const struct chv_community southwest_community = { + .uid = "1", + .pins = southwest_pins, + .npins = ARRAY_SIZE(southwest_pins), + .groups = southwest_groups, + .ngroups = ARRAY_SIZE(southwest_groups), + .functions = southwest_functions, + .nfunctions = ARRAY_SIZE(southwest_functions), + .gpio_ranges = southwest_gpio_ranges, + .ngpio_ranges = ARRAY_SIZE(southwest_gpio_ranges), + .ngpios = ARRAY_SIZE(southwest_pins), +}; + +static const struct pinctrl_pin_desc north_pins[] = { + PINCTRL_PIN(0, "GPIO_DFX_0"), + PINCTRL_PIN(1, "GPIO_DFX_3"), + PINCTRL_PIN(2, "GPIO_DFX_7"), + PINCTRL_PIN(3, "GPIO_DFX_1"), + PINCTRL_PIN(4, "GPIO_DFX_5"), + PINCTRL_PIN(5, "GPIO_DFX_4"), + PINCTRL_PIN(6, "GPIO_DFX_8"), + PINCTRL_PIN(7, "GPIO_DFX_2"), + PINCTRL_PIN(8, "GPIO_DFX_6"), + + PINCTRL_PIN(15, "GPIO_SUS0"), + PINCTRL_PIN(16, "SEC_GPIO_SUS10"), + PINCTRL_PIN(17, "GPIO_SUS3"), + PINCTRL_PIN(18, "GPIO_SUS7"), + PINCTRL_PIN(19, "GPIO_SUS1"), + PINCTRL_PIN(20, "GPIO_SUS5"), + PINCTRL_PIN(21, "SEC_GPIO_SUS11"), + PINCTRL_PIN(22, "GPIO_SUS4"), + PINCTRL_PIN(23, "SEC_GPIO_SUS8"), + PINCTRL_PIN(24, "GPIO_SUS2"), + PINCTRL_PIN(25, "GPIO_SUS6"), + PINCTRL_PIN(26, "CX_PREQ_B"), + PINCTRL_PIN(27, "SEC_GPIO_SUS9"), + + PINCTRL_PIN(30, "TRST_B"), + PINCTRL_PIN(31, "TCK"), + PINCTRL_PIN(32, "PROCHOT_B"), + PINCTRL_PIN(33, "SVIDO_DATA"), + PINCTRL_PIN(34, "TMS"), + PINCTRL_PIN(35, "CX_PRDY_B_2"), + PINCTRL_PIN(36, "TDO_2"), + PINCTRL_PIN(37, "CX_PRDY_B"), + PINCTRL_PIN(38, "SVIDO_ALERT_B"), + PINCTRL_PIN(39, "TDO"), + PINCTRL_PIN(40, "SVIDO_CLK"), + PINCTRL_PIN(41, "TDI"), + + PINCTRL_PIN(45, "GP_CAMERASB_05"), + PINCTRL_PIN(46, "GP_CAMERASB_02"), + PINCTRL_PIN(47, "GP_CAMERASB_08"), + PINCTRL_PIN(48, "GP_CAMERASB_00"), + PINCTRL_PIN(49, "GP_CAMERASB_06"), + PINCTRL_PIN(50, "GP_CAMERASB_10"), + PINCTRL_PIN(51, "GP_CAMERASB_03"), + PINCTRL_PIN(52, "GP_CAMERASB_09"), + PINCTRL_PIN(53, "GP_CAMERASB_01"), + PINCTRL_PIN(54, "GP_CAMERASB_07"), + PINCTRL_PIN(55, "GP_CAMERASB_11"), + PINCTRL_PIN(56, "GP_CAMERASB_04"), + + PINCTRL_PIN(60, "PANEL0_BKLTEN"), + PINCTRL_PIN(61, "HV_DDI0_HPD"), + PINCTRL_PIN(62, "HV_DDI2_DDC_SDA"), + PINCTRL_PIN(63, "PANEL1_BKLTCTL"), + PINCTRL_PIN(64, "HV_DDI1_HPD"), + PINCTRL_PIN(65, "PANEL0_BKLTCTL"), + PINCTRL_PIN(66, "HV_DDI0_DDC_SDA"), + PINCTRL_PIN(67, "HV_DDI2_DDC_SCL"), + PINCTRL_PIN(68, "HV_DDI2_HPD"), + PINCTRL_PIN(69, "PANEL1_VDDEN"), + PINCTRL_PIN(70, "PANEL1_BKLTEN"), + PINCTRL_PIN(71, "HV_DDI0_DDC_SCL"), + PINCTRL_PIN(72, "PANEL0_VDDEN"), +}; + +static const struct chv_gpio_pinrange north_gpio_ranges[] = { + GPIO_PINRANGE(0, 8), + GPIO_PINRANGE(15, 27), + GPIO_PINRANGE(30, 41), + GPIO_PINRANGE(45, 56), + GPIO_PINRANGE(60, 72), +}; + +static const struct chv_community north_community = { + .uid = "2", + .pins = north_pins, + .npins = ARRAY_SIZE(north_pins), + .gpio_ranges = north_gpio_ranges, + .ngpio_ranges = ARRAY_SIZE(north_gpio_ranges), + .ngpios = ARRAY_SIZE(north_pins), +}; + +static const struct pinctrl_pin_desc east_pins[] = { + PINCTRL_PIN(0, "PMU_SLP_S3_B"), + PINCTRL_PIN(1, "PMU_BATLOW_B"), + PINCTRL_PIN(2, "SUS_STAT_B"), + PINCTRL_PIN(3, "PMU_SLP_S0IX_B"), + PINCTRL_PIN(4, "PMU_AC_PRESENT"), + PINCTRL_PIN(5, "PMU_PLTRST_B"), + PINCTRL_PIN(6, "PMU_SUSCLK"), + PINCTRL_PIN(7, "PMU_SLP_LAN_B"), + PINCTRL_PIN(8, "PMU_PWRBTN_B"), + PINCTRL_PIN(9, "PMU_SLP_S4_B"), + PINCTRL_PIN(10, "PMU_WAKE_B"), + PINCTRL_PIN(11, "PMU_WAKE_LAN_B"), + + PINCTRL_PIN(15, "MF_ISH_GPIO_3"), + PINCTRL_PIN(16, "MF_ISH_GPIO_7"), + PINCTRL_PIN(17, "MF_ISH_I2C1_SCL"), + PINCTRL_PIN(18, "MF_ISH_GPIO_1"), + PINCTRL_PIN(19, "MF_ISH_GPIO_5"), + PINCTRL_PIN(20, "MF_ISH_GPIO_9"), + PINCTRL_PIN(21, "MF_ISH_GPIO_0"), + PINCTRL_PIN(22, "MF_ISH_GPIO_4"), + PINCTRL_PIN(23, "MF_ISH_GPIO_8"), + PINCTRL_PIN(24, "MF_ISH_GPIO_2"), + PINCTRL_PIN(25, "MF_ISH_GPIO_6"), + PINCTRL_PIN(26, "MF_ISH_I2C1_SDA"), +}; + +static const struct chv_gpio_pinrange east_gpio_ranges[] = { + GPIO_PINRANGE(0, 11), + GPIO_PINRANGE(15, 26), +}; + +static const struct chv_community east_community = { + .uid = "3", + .pins = east_pins, + .npins = ARRAY_SIZE(east_pins), + .gpio_ranges = east_gpio_ranges, + .ngpio_ranges = ARRAY_SIZE(east_gpio_ranges), + .ngpios = ARRAY_SIZE(east_pins), +}; + +static const struct pinctrl_pin_desc southeast_pins[] = { + PINCTRL_PIN(0, "MF_PLT_CLK0"), + PINCTRL_PIN(1, "PWM1"), + PINCTRL_PIN(2, "MF_PLT_CLK1"), + PINCTRL_PIN(3, "MF_PLT_CLK4"), + PINCTRL_PIN(4, "MF_PLT_CLK3"), + PINCTRL_PIN(5, "PWM0"), + PINCTRL_PIN(6, "MF_PLT_CLK5"), + PINCTRL_PIN(7, "MF_PLT_CLK2"), + + PINCTRL_PIN(15, "SDMMC2_D3_CD_B"), + PINCTRL_PIN(16, "SDMMC1_CLK"), + PINCTRL_PIN(17, "SDMMC1_D0"), + PINCTRL_PIN(18, "SDMMC2_D1"), + PINCTRL_PIN(19, "SDMMC2_CLK"), + PINCTRL_PIN(20, "SDMMC1_D2"), + PINCTRL_PIN(21, "SDMMC2_D2"), + PINCTRL_PIN(22, "SDMMC2_CMD"), + PINCTRL_PIN(23, "SDMMC1_CMD"), + PINCTRL_PIN(24, "SDMMC1_D1"), + PINCTRL_PIN(25, "SDMMC2_D0"), + PINCTRL_PIN(26, "SDMMC1_D3_CD_B"), + + PINCTRL_PIN(30, "SDMMC3_D1"), + PINCTRL_PIN(31, "SDMMC3_CLK"), + PINCTRL_PIN(32, "SDMMC3_D3"), + PINCTRL_PIN(33, "SDMMC3_D2"), + PINCTRL_PIN(34, "SDMMC3_CMD"), + PINCTRL_PIN(35, "SDMMC3_D0"), + + PINCTRL_PIN(45, "MF_LPC_AD2"), + PINCTRL_PIN(46, "LPC_CLKRUNB"), + PINCTRL_PIN(47, "MF_LPC_AD0"), + PINCTRL_PIN(48, "LPC_FRAMEB"), + PINCTRL_PIN(49, "MF_LPC_CLKOUT1"), + PINCTRL_PIN(50, "MF_LPC_AD3"), + PINCTRL_PIN(51, "MF_LPC_CLKOUT0"), + PINCTRL_PIN(52, "MF_LPC_AD1"), + + PINCTRL_PIN(60, "SPI1_MISO"), + PINCTRL_PIN(61, "SPI1_CSO_B"), + PINCTRL_PIN(62, "SPI1_CLK"), + PINCTRL_PIN(63, "MMC1_D6"), + PINCTRL_PIN(64, "SPI1_MOSI"), + PINCTRL_PIN(65, "MMC1_D5"), + PINCTRL_PIN(66, "SPI1_CS1_B"), + PINCTRL_PIN(67, "MMC1_D4_SD_WE"), + PINCTRL_PIN(68, "MMC1_D7"), + PINCTRL_PIN(69, "MMC1_RCLK"), + + PINCTRL_PIN(75, "USB_OC1_B"), + PINCTRL_PIN(76, "PMU_RESETBUTTON_B"), + PINCTRL_PIN(77, "GPIO_ALERT"), + PINCTRL_PIN(78, "SDMMC3_PWR_EN_B"), + PINCTRL_PIN(79, "ILB_SERIRQ"), + PINCTRL_PIN(80, "USB_OC0_B"), + PINCTRL_PIN(81, "SDMMC3_CD_B"), + PINCTRL_PIN(82, "SPKR"), + PINCTRL_PIN(83, "SUSPWRDNACK"), + PINCTRL_PIN(84, "SPARE_PIN"), + PINCTRL_PIN(85, "SDMMC3_1P8_EN"), +}; + +static const unsigned southeast_pwm0_pins[] = { 5 }; +static const unsigned southeast_pwm1_pins[] = { 1 }; +static const unsigned southeast_sdmmc1_pins[] = { + 16, 17, 20, 23, 24, 26, 63, 65, 67, 68, 69, +}; +static const unsigned southeast_sdmmc2_pins[] = { 15, 18, 19, 21, 22, 25 }; +static const unsigned southeast_sdmmc3_pins[] = { + 30, 31, 32, 33, 34, 35, 78, 81, 85, +}; +static const unsigned southeast_spi1_pins[] = { 60, 61, 62, 64, 66 }; +static const unsigned southeast_spi2_pins[] = { 2, 3, 4, 6, 7 }; + +static const struct chv_pingroup southeast_groups[] = { + PIN_GROUP("pwm0_grp", southeast_pwm0_pins, 1, false), + PIN_GROUP("pwm1_grp", southeast_pwm1_pins, 1, false), + PIN_GROUP("sdmmc1_grp", southeast_sdmmc1_pins, 1, false), + PIN_GROUP("sdmmc2_grp", southeast_sdmmc2_pins, 1, false), + PIN_GROUP("sdmmc3_grp", southeast_sdmmc3_pins, 1, false), + PIN_GROUP("spi1_grp", southeast_spi1_pins, 1, false), + PIN_GROUP("spi2_grp", southeast_spi2_pins, 4, false), +}; + +static const char * const southeast_pwm0_groups[] = { "pwm0_grp" }; +static const char * const southeast_pwm1_groups[] = { "pwm1_grp" }; +static const char * const southeast_sdmmc1_groups[] = { "sdmmc1_grp" }; +static const char * const southeast_sdmmc2_groups[] = { "sdmmc2_grp" }; +static const char * const southeast_sdmmc3_groups[] = { "sdmmc3_grp" }; +static const char * const southeast_spi1_groups[] = { "spi1_grp" }; +static const char * const southeast_spi2_groups[] = { "spi2_grp" }; + +static const struct chv_function southeast_functions[] = { + FUNCTION("pwm0", southeast_pwm0_groups), + FUNCTION("pwm1", southeast_pwm1_groups), + FUNCTION("sdmmc1", southeast_sdmmc1_groups), + FUNCTION("sdmmc2", southeast_sdmmc2_groups), + FUNCTION("sdmmc3", southeast_sdmmc3_groups), + FUNCTION("spi1", southeast_spi1_groups), + FUNCTION("spi2", southeast_spi2_groups), +}; + +static const struct chv_gpio_pinrange southeast_gpio_ranges[] = { + GPIO_PINRANGE(0, 7), + GPIO_PINRANGE(15, 26), + GPIO_PINRANGE(30, 35), + GPIO_PINRANGE(45, 52), + GPIO_PINRANGE(60, 69), + GPIO_PINRANGE(75, 85), +}; + +static const struct chv_community southeast_community = { + .uid = "4", + .pins = southeast_pins, + .npins = ARRAY_SIZE(southeast_pins), + .groups = southeast_groups, + .ngroups = ARRAY_SIZE(southeast_groups), + .functions = southeast_functions, + .nfunctions = ARRAY_SIZE(southeast_functions), + .gpio_ranges = southeast_gpio_ranges, + .ngpio_ranges = ARRAY_SIZE(southeast_gpio_ranges), + .ngpios = ARRAY_SIZE(southeast_pins), +}; + +static const struct chv_community *chv_communities[] = { + &southwest_community, + &north_community, + &east_community, + &southeast_community, +}; + +static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned offset, + unsigned reg) +{ + unsigned family_no = offset / MAX_FAMILY_PAD_GPIO_NO; + unsigned pad_no = offset % MAX_FAMILY_PAD_GPIO_NO; + + offset = FAMILY_PAD_REGS_OFF + FAMILY_PAD_REGS_SIZE * family_no + + GPIO_REGS_SIZE * pad_no; + + return pctrl->regs + offset + reg; +} + +static void chv_writel(u32 value, void __iomem *reg) +{ + writel(value, reg); + /* simple readback to confirm the bus transferring done */ + readl(reg); +} + +/* When Pad Cfg is locked, driver can only change GPIOTXState or GPIORXState */ +static bool chv_pad_locked(struct chv_pinctrl *pctrl, unsigned offset) +{ + void __iomem *reg; + + reg = chv_padreg(pctrl, offset, CHV_PADCTRL1); + return readl(reg) & CHV_PADCTRL1_CFGLOCK; +} + +static int chv_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->community->ngroups; +} + +static const char *chv_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->community->groups[group].name; +} + +static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, + const unsigned **pins, unsigned *npins) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = pctrl->community->groups[group].pins; + *npins = pctrl->community->groups[group].npins; + return 0; +} + +static void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned long flags; + u32 ctrl0, ctrl1; + bool locked; + + spin_lock_irqsave(&pctrl->lock, flags); + + ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0)); + ctrl1 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL1)); + locked = chv_pad_locked(pctrl, offset); + + spin_unlock_irqrestore(&pctrl->lock, flags); + + if (ctrl0 & CHV_PADCTRL0_GPIOEN) { + seq_puts(s, "GPIO "); + } else { + u32 mode; + + mode = ctrl0 & CHV_PADCTRL0_PMODE_MASK; + mode >>= CHV_PADCTRL0_PMODE_SHIFT; + + seq_printf(s, "mode %d ", mode); + } + + seq_printf(s, "ctrl0 0x%08x ctrl1 0x%08x", ctrl0, ctrl1); + + if (locked) + seq_puts(s, " [LOCKED]"); +} + +static const struct pinctrl_ops chv_pinctrl_ops = { + .get_groups_count = chv_get_groups_count, + .get_group_name = chv_get_group_name, + .get_group_pins = chv_get_group_pins, + .pin_dbg_show = chv_pin_dbg_show, +}; + +static int chv_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->community->nfunctions; +} + +static const char *chv_get_function_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->community->functions[function].name; +} + +static int chv_get_function_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const ngroups) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pctrl->community->functions[function].groups; + *ngroups = pctrl->community->functions[function].ngroups; + return 0; +} + +static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, + unsigned group) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct chv_pingroup *grp; + unsigned long flags; + int i; + + grp = &pctrl->community->groups[group]; + + spin_lock_irqsave(&pctrl->lock, flags); + + /* Check first that the pad is not locked */ + for (i = 0; i < grp->npins; i++) { + if (chv_pad_locked(pctrl, grp->pins[i])) { + dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n", + grp->pins[i]); + spin_unlock_irqrestore(&pctrl->lock, flags); + return -EBUSY; + } + } + + for (i = 0; i < grp->npins; i++) { + const struct chv_alternate_function *altfunc = &grp->altfunc; + int pin = grp->pins[i]; + void __iomem *reg; + u32 value; + + /* Check if there is pin-specific config */ + if (grp->overrides) { + int j; + + for (j = 0; j < grp->noverrides; j++) { + if (grp->overrides[j].pin == pin) { + altfunc = &grp->overrides[j]; + break; + } + } + } + + reg = chv_padreg(pctrl, pin, CHV_PADCTRL0); + value = readl(reg); + /* Disable GPIO mode */ + value &= ~CHV_PADCTRL0_GPIOEN; + /* Set to desired mode */ + value &= ~CHV_PADCTRL0_PMODE_MASK; + value |= altfunc->mode << CHV_PADCTRL0_PMODE_SHIFT; + chv_writel(value, reg); + + /* Update for invert_oe */ + reg = chv_padreg(pctrl, pin, CHV_PADCTRL1); + value = readl(reg) & ~CHV_PADCTRL1_INVRXTX_MASK; + if (altfunc->invert_oe) + value |= CHV_PADCTRL1_INVRXTX_TXENABLE; + chv_writel(value, reg); + + dev_dbg(pctrl->dev, "configured pin %u mode %u OE %sinverted\n", + pin, altfunc->mode, altfunc->invert_oe ? "" : "not "); + } + + spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static int chv_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned long flags; + void __iomem *reg; + u32 value; + + spin_lock_irqsave(&pctrl->lock, flags); + + if (chv_pad_locked(pctrl, offset)) { + value = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0)); + if (!(value & CHV_PADCTRL0_GPIOEN)) { + /* Locked so cannot enable */ + spin_unlock_irqrestore(&pctrl->lock, flags); + return -EBUSY; + } + } else { + int i; + + /* Reset the interrupt mapping */ + for (i = 0; i < ARRAY_SIZE(pctrl->intr_lines); i++) { + if (pctrl->intr_lines[i] == offset) { + pctrl->intr_lines[i] = 0; + break; + } + } + + /* Disable interrupt generation */ + reg = chv_padreg(pctrl, offset, CHV_PADCTRL1); + value = readl(reg); + value &= ~CHV_PADCTRL1_INTWAKECFG_MASK; + value &= ~CHV_PADCTRL1_INVRXTX_MASK; + chv_writel(value, reg); + + /* Switch to a GPIO mode */ + reg = chv_padreg(pctrl, offset, CHV_PADCTRL0); + value = readl(reg) | CHV_PADCTRL0_GPIOEN; + chv_writel(value, reg); + } + + spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static void chv_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned long flags; + void __iomem *reg; + u32 value; + + spin_lock_irqsave(&pctrl->lock, flags); + + reg = chv_padreg(pctrl, offset, CHV_PADCTRL0); + value = readl(reg) & ~CHV_PADCTRL0_GPIOEN; + chv_writel(value, reg); + + spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static int chv_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset, bool input) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + void __iomem *reg = chv_padreg(pctrl, offset, CHV_PADCTRL0); + unsigned long flags; + u32 ctrl0; + + spin_lock_irqsave(&pctrl->lock, flags); + + ctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIOCFG_MASK; + if (input) + ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPI << CHV_PADCTRL0_GPIOCFG_SHIFT; + else + ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPO << CHV_PADCTRL0_GPIOCFG_SHIFT; + chv_writel(ctrl0, reg); + + spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static const struct pinmux_ops chv_pinmux_ops = { + .get_functions_count = chv_get_functions_count, + .get_function_name = chv_get_function_name, + .get_function_groups = chv_get_function_groups, + .set_mux = chv_pinmux_set_mux, + .gpio_request_enable = chv_gpio_request_enable, + .gpio_disable_free = chv_gpio_disable_free, + .gpio_set_direction = chv_gpio_set_direction, +}; + +static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *config) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + unsigned long flags; + u32 ctrl0, ctrl1; + u16 arg = 0; + u32 term; + + spin_lock_irqsave(&pctrl->lock, flags); + ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + ctrl1 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL1)); + spin_unlock_irqrestore(&pctrl->lock, flags); + + term = (ctrl0 & CHV_PADCTRL0_TERM_MASK) >> CHV_PADCTRL0_TERM_SHIFT; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (term) + return -EINVAL; + break; + + case PIN_CONFIG_BIAS_PULL_UP: + if (!(ctrl0 & CHV_PADCTRL0_TERM_UP)) + return -EINVAL; + + switch (term) { + case CHV_PADCTRL0_TERM_20K: + arg = 20000; + break; + case CHV_PADCTRL0_TERM_5K: + arg = 5000; + break; + case CHV_PADCTRL0_TERM_1K: + arg = 1000; + break; + } + + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + if (!term || (ctrl0 & CHV_PADCTRL0_TERM_UP)) + return -EINVAL; + + switch (term) { + case CHV_PADCTRL0_TERM_20K: + arg = 20000; + break; + case CHV_PADCTRL0_TERM_5K: + arg = 5000; + break; + } + + break; + + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (!(ctrl1 & CHV_PADCTRL1_ODEN)) + return -EINVAL; + break; + + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: { + u32 cfg; + + cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; + cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT; + if (cfg != CHV_PADCTRL0_GPIOCFG_HIZ) + return -EINVAL; + + break; + } + + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, + enum pin_config_param param, u16 arg) +{ + void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL0); + unsigned long flags; + u32 ctrl0, pull; + + spin_lock_irqsave(&pctrl->lock, flags); + ctrl0 = readl(reg); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + ctrl0 &= ~(CHV_PADCTRL0_TERM_MASK | CHV_PADCTRL0_TERM_UP); + break; + + case PIN_CONFIG_BIAS_PULL_UP: + ctrl0 &= ~(CHV_PADCTRL0_TERM_MASK | CHV_PADCTRL0_TERM_UP); + + switch (arg) { + case 1000: + /* For 1k there is only pull up */ + pull = CHV_PADCTRL0_TERM_1K << CHV_PADCTRL0_TERM_SHIFT; + break; + case 5000: + pull = CHV_PADCTRL0_TERM_5K << CHV_PADCTRL0_TERM_SHIFT; + break; + case 20000: + pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT; + break; + default: + spin_unlock_irqrestore(&pctrl->lock, flags); + return -EINVAL; + } + + ctrl0 |= CHV_PADCTRL0_TERM_UP | pull; + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + ctrl0 &= ~(CHV_PADCTRL0_TERM_MASK | CHV_PADCTRL0_TERM_UP); + + switch (arg) { + case 5000: + pull = CHV_PADCTRL0_TERM_5K << CHV_PADCTRL0_TERM_SHIFT; + break; + case 20000: + pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT; + break; + default: + spin_unlock_irqrestore(&pctrl->lock, flags); + return -EINVAL; + } + + ctrl0 |= pull; + break; + + default: + spin_unlock_irqrestore(&pctrl->lock, flags); + return -EINVAL; + } + + chv_writel(ctrl0, reg); + spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *configs, unsigned nconfigs) +{ + struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param; + int i, ret; + u16 arg; + + if (chv_pad_locked(pctrl, pin)) + return -EBUSY; + + for (i = 0; i < nconfigs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = chv_config_set_pull(pctrl, pin, param, arg); + if (ret) + return ret; + break; + + default: + return -ENOTSUPP; + } + + dev_dbg(pctrl->dev, "pin %d set config %d arg %u\n", pin, + param, arg); + } + + return 0; +} + +static const struct pinconf_ops chv_pinconf_ops = { + .is_generic = true, + .pin_config_set = chv_config_set, + .pin_config_get = chv_config_get, +}; + +static struct pinctrl_desc chv_pinctrl_desc = { + .pctlops = &chv_pinctrl_ops, + .pmxops = &chv_pinmux_ops, + .confops = &chv_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int chv_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void chv_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(chip->base + offset); +} + +static unsigned chv_gpio_offset_to_pin(struct chv_pinctrl *pctrl, + unsigned offset) +{ + return pctrl->community->pins[offset].number; +} + +static int chv_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip); + int pin = chv_gpio_offset_to_pin(pctrl, offset); + u32 ctrl0, cfg; + + ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + + cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; + cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT; + + if (cfg == CHV_PADCTRL0_GPIOCFG_GPO) + return !!(ctrl0 & CHV_PADCTRL0_GPIOTXSTATE); + return !!(ctrl0 & CHV_PADCTRL0_GPIORXSTATE); +} + +static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip); + unsigned pin = chv_gpio_offset_to_pin(pctrl, offset); + unsigned long flags; + void __iomem *reg; + u32 ctrl0; + + spin_lock_irqsave(&pctrl->lock, flags); + + reg = chv_padreg(pctrl, pin, CHV_PADCTRL0); + ctrl0 = readl(reg); + + if (value) + ctrl0 |= CHV_PADCTRL0_GPIOTXSTATE; + else + ctrl0 &= ~CHV_PADCTRL0_GPIOTXSTATE; + + chv_writel(ctrl0, reg); + + spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip); + unsigned pin = chv_gpio_offset_to_pin(pctrl, offset); + u32 ctrl0, direction; + + ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + + direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; + direction >>= CHV_PADCTRL0_GPIOCFG_SHIFT; + + return direction != CHV_PADCTRL0_GPIOCFG_GPO; +} + +static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_gpio_direction_input(chip->base + offset); +} + +static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + return pinctrl_gpio_direction_output(chip->base + offset); +} + +static const struct gpio_chip chv_gpio_chip = { + .owner = THIS_MODULE, + .request = chv_gpio_request, + .free = chv_gpio_free, + .get_direction = chv_gpio_get_direction, + .direction_input = chv_gpio_direction_input, + .direction_output = chv_gpio_direction_output, + .get = chv_gpio_get, + .set = chv_gpio_set, +}; + +static void chv_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc); + int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d)); + u32 intr_line; + + spin_lock(&pctrl->lock); + + intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + intr_line &= CHV_PADCTRL0_INTSEL_MASK; + intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT; + chv_writel(BIT(intr_line), pctrl->regs + CHV_INTSTAT); + + spin_unlock(&pctrl->lock); +} + +static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc); + int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d)); + u32 value, intr_line; + unsigned long flags; + + spin_lock_irqsave(&pctrl->lock, flags); + + intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + intr_line &= CHV_PADCTRL0_INTSEL_MASK; + intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT; + + value = readl(pctrl->regs + CHV_INTMASK); + if (mask) + value &= ~BIT(intr_line); + else + value |= BIT(intr_line); + chv_writel(value, pctrl->regs + CHV_INTMASK); + + spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static void chv_gpio_irq_mask(struct irq_data *d) +{ + chv_gpio_irq_mask_unmask(d, true); +} + +static void chv_gpio_irq_unmask(struct irq_data *d) +{ + chv_gpio_irq_mask_unmask(d, false); +} + +static int chv_gpio_irq_type(struct irq_data *d, unsigned type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc); + unsigned offset = irqd_to_hwirq(d); + int pin = chv_gpio_offset_to_pin(pctrl, offset); + unsigned long flags; + u32 value; + + spin_lock_irqsave(&pctrl->lock, flags); + + /* + * Pins which can be used as shared interrupt are configured in + * BIOS. Driver trusts BIOS configurations and assigns different + * handler according to the irq type. + * + * Driver needs to save the mapping between each pin and + * its interrupt line. + * 1. If the pin cfg is locked in BIOS: + * Trust BIOS has programmed IntWakeCfg bits correctly, + * driver just needs to save the mapping. + * 2. If the pin cfg is not locked in BIOS: + * Driver programs the IntWakeCfg bits and save the mapping. + */ + if (!chv_pad_locked(pctrl, pin)) { + void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL1); + + value = readl(reg); + value &= ~CHV_PADCTRL1_INTWAKECFG_MASK; + value &= ~CHV_PADCTRL1_INVRXTX_MASK; + + if (type & IRQ_TYPE_EDGE_BOTH) { + if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) + value |= CHV_PADCTRL1_INTWAKECFG_BOTH; + else if (type & IRQ_TYPE_EDGE_RISING) + value |= CHV_PADCTRL1_INTWAKECFG_RISING; + else if (type & IRQ_TYPE_EDGE_FALLING) + value |= CHV_PADCTRL1_INTWAKECFG_FALLING; + } else if (type & IRQ_TYPE_LEVEL_MASK) { + value |= CHV_PADCTRL1_INTWAKECFG_LEVEL; + if (type & IRQ_TYPE_LEVEL_LOW) + value |= CHV_PADCTRL1_INVRXTX_RXDATA; + } + + chv_writel(value, reg); + } + + value = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + value &= CHV_PADCTRL0_INTSEL_MASK; + value >>= CHV_PADCTRL0_INTSEL_SHIFT; + + pctrl->intr_lines[value] = offset; + + if (type & IRQ_TYPE_EDGE_BOTH) + __irq_set_handler_locked(d->irq, handle_edge_irq); + else if (type & IRQ_TYPE_LEVEL_MASK) + __irq_set_handler_locked(d->irq, handle_level_irq); + + spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static struct irq_chip chv_gpio_irqchip = { + .name = "chv-gpio", + .irq_ack = chv_gpio_irq_ack, + .irq_mask = chv_gpio_irq_mask, + .irq_unmask = chv_gpio_irq_unmask, + .irq_set_type = chv_gpio_irq_type, + .flags = IRQCHIP_SKIP_SET_WAKE, +}; + +static void chv_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc); + struct irq_chip *chip = irq_get_chip(irq); + unsigned long pending; + u32 intr_line; + + chained_irq_enter(chip, desc); + + pending = readl(pctrl->regs + CHV_INTSTAT); + for_each_set_bit(intr_line, &pending, 16) { + unsigned irq, offset; + + offset = pctrl->intr_lines[intr_line]; + irq = irq_find_mapping(gc->irqdomain, offset); + generic_handle_irq(irq); + } + + chained_irq_exit(chip, desc); +} + +static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) +{ + const struct chv_gpio_pinrange *range; + struct gpio_chip *chip = &pctrl->chip; + int ret, i, offset; + + *chip = chv_gpio_chip; + + chip->ngpio = pctrl->community->ngpios; + chip->label = dev_name(pctrl->dev); + chip->dev = pctrl->dev; + chip->base = -1; + + ret = gpiochip_add(chip); + if (ret) { + dev_err(pctrl->dev, "Failed to register gpiochip\n"); + return ret; + } + + for (i = 0, offset = 0; i < pctrl->community->ngpio_ranges; i++) { + range = &pctrl->community->gpio_ranges[i]; + ret = gpiochip_add_pin_range(chip, dev_name(pctrl->dev), offset, + range->base, range->npins); + if (ret) { + dev_err(pctrl->dev, "failed to add GPIO pin range\n"); + goto fail; + } + + offset += range->npins; + } + + /* Mask and clear all interrupts */ + chv_writel(0, pctrl->regs + CHV_INTMASK); + chv_writel(0xffff, pctrl->regs + CHV_INTSTAT); + + ret = gpiochip_irqchip_add(chip, &chv_gpio_irqchip, 0, + handle_simple_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(pctrl->dev, "failed to add IRQ chip\n"); + goto fail; + } + + gpiochip_set_chained_irqchip(chip, &chv_gpio_irqchip, irq, + chv_gpio_irq_handler); + return 0; + +fail: + gpiochip_remove(chip); + + return ret; +} + +static int chv_pinctrl_probe(struct platform_device *pdev) +{ + struct chv_pinctrl *pctrl; + struct acpi_device *adev; + struct resource *res; + int ret, irq, i; + + adev = ACPI_COMPANION(&pdev->dev); + if (!adev) + return -ENODEV; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(chv_communities); i++) + if (!strcmp(adev->pnp.unique_id, chv_communities[i]->uid)) { + pctrl->community = chv_communities[i]; + break; + } + if (i == ARRAY_SIZE(chv_communities)) + return -ENODEV; + + spin_lock_init(&pctrl->lock); + pctrl->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pctrl->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pctrl->regs)) + return PTR_ERR(pctrl->regs); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get interrupt number\n"); + return irq; + } + + pctrl->pctldesc = chv_pinctrl_desc; + pctrl->pctldesc.name = dev_name(&pdev->dev); + pctrl->pctldesc.pins = pctrl->community->pins; + pctrl->pctldesc.npins = pctrl->community->npins; + + pctrl->pctldev = pinctrl_register(&pctrl->pctldesc, &pdev->dev, pctrl); + if (!pctrl->pctldev) { + dev_err(&pdev->dev, "failed to register pinctrl driver\n"); + return -ENODEV; + } + + ret = chv_gpio_probe(pctrl, irq); + if (ret) { + pinctrl_unregister(pctrl->pctldev); + return ret; + } + + platform_set_drvdata(pdev, pctrl); + + return 0; +} + +static int chv_pinctrl_remove(struct platform_device *pdev) +{ + struct chv_pinctrl *pctrl = platform_get_drvdata(pdev); + + gpiochip_remove(&pctrl->chip); + pinctrl_unregister(pctrl->pctldev); + + return 0; +} + +static const struct acpi_device_id chv_pinctrl_acpi_match[] = { + { "INT33FF" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, chv_pinctrl_acpi_match); + +static struct platform_driver chv_pinctrl_driver = { + .probe = chv_pinctrl_probe, + .remove = chv_pinctrl_remove, + .driver = { + .name = "cherryview-pinctrl", + .owner = THIS_MODULE, + .acpi_match_table = chv_pinctrl_acpi_match, + }, +}; + +static int __init chv_pinctrl_init(void) +{ + return platform_driver_register(&chv_pinctrl_driver); +} +subsys_initcall(chv_pinctrl_init); + +static void __exit chv_pinctrl_exit(void) +{ + platform_driver_unregister(&chv_pinctrl_driver); +} +module_exit(chv_pinctrl_exit); + +MODULE_AUTHOR("Mika Westerberg "); +MODULE_DESCRIPTION("Intel Cherryview/Braswell pinctrl driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.1 From 87993273feb7f9379ec79cd9c25d195c4b93b7da Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Sep 2014 21:05:37 +0200 Subject: pinctrl: samsung: Make samsung_pinctrl_get_soc_data use ERR_PTR() Currently the function returns a valid pointer on success and NULL on error, so exact error code is lost. This patch changes return convention of the function to use ERR_PTR() on error instead. Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-samsung.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 2d37c8f..8ac7503 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -981,7 +981,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( id = of_alias_get_id(node, "pinctrl"); if (id < 0) { dev_err(&pdev->dev, "failed to get alias id\n"); - return NULL; + return ERR_PTR(-ENOENT); } match = of_match_node(samsung_pinctrl_dt_match, node); ctrl = (struct samsung_pin_ctrl *)match->data + id; @@ -1033,9 +1033,9 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) } ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev); - if (!ctrl) { + if (IS_ERR(ctrl)) { dev_err(&pdev->dev, "driver data not available\n"); - return -EINVAL; + return PTR_ERR(ctrl); } drvdata->ctrl = ctrl; drvdata->dev = dev; -- cgit v1.1 From e06deff967d29beffceeaffc4cdc90aacbd34898 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Sep 2014 21:05:38 +0200 Subject: pinctrl: samsung: Drop unused label field in samsung_pin_ctrl struct There is no code using it and in fact there are pin controller variants that do not even have this field initialized in their init data. This patch removes it completely. Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-exynos.c | 22 ---------------------- drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 4 ---- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 1 - drivers/pinctrl/samsung/pinctrl-samsung.h | 3 --- 4 files changed, 30 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index d7154ed..7e6463f 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -682,7 +682,6 @@ struct samsung_pin_ctrl s5pv210_pin_ctrl[] = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "s5pv210-gpio-ctrl0", }, }; @@ -729,7 +728,6 @@ struct samsung_pin_ctrl exynos3250_pin_ctrl[] = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos3250-gpio-ctrl0", }, { /* pin-controller instance 1 data */ .pin_banks = exynos3250_pin_banks1, @@ -738,7 +736,6 @@ struct samsung_pin_ctrl exynos3250_pin_ctrl[] = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos3250-gpio-ctrl1", }, }; @@ -803,7 +800,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos4210-gpio-ctrl0", }, { /* pin-controller instance 1 data */ .pin_banks = exynos4210_pin_banks1, @@ -812,12 +808,10 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos4210-gpio-ctrl1", }, { /* pin-controller instance 2 data */ .pin_banks = exynos4210_pin_banks2, .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2), - .label = "exynos4210-gpio-ctrl2", }, }; @@ -891,7 +885,6 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos4x12-gpio-ctrl0", }, { /* pin-controller instance 1 data */ .pin_banks = exynos4x12_pin_banks1, @@ -900,7 +893,6 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos4x12-gpio-ctrl1", }, { /* pin-controller instance 2 data */ .pin_banks = exynos4x12_pin_banks2, @@ -908,7 +900,6 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos4x12-gpio-ctrl2", }, { /* pin-controller instance 3 data */ .pin_banks = exynos4x12_pin_banks3, @@ -916,7 +907,6 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos4x12-gpio-ctrl3", }, }; @@ -989,7 +979,6 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos5250-gpio-ctrl0", }, { /* pin-controller instance 1 data */ .pin_banks = exynos5250_pin_banks1, @@ -997,7 +986,6 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos5250-gpio-ctrl1", }, { /* pin-controller instance 2 data */ .pin_banks = exynos5250_pin_banks2, @@ -1005,7 +993,6 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos5250-gpio-ctrl2", }, { /* pin-controller instance 3 data */ .pin_banks = exynos5250_pin_banks3, @@ -1013,7 +1000,6 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, - .label = "exynos5250-gpio-ctrl3", }, }; @@ -1068,19 +1054,16 @@ struct samsung_pin_ctrl exynos5260_pin_ctrl[] = { .nr_banks = ARRAY_SIZE(exynos5260_pin_banks0), .eint_gpio_init = exynos_eint_gpio_init, .eint_wkup_init = exynos_eint_wkup_init, - .label = "exynos5260-gpio-ctrl0", }, { /* pin-controller instance 1 data */ .pin_banks = exynos5260_pin_banks1, .nr_banks = ARRAY_SIZE(exynos5260_pin_banks1), .eint_gpio_init = exynos_eint_gpio_init, - .label = "exynos5260-gpio-ctrl1", }, { /* pin-controller instance 2 data */ .pin_banks = exynos5260_pin_banks2, .nr_banks = ARRAY_SIZE(exynos5260_pin_banks2), .eint_gpio_init = exynos_eint_gpio_init, - .label = "exynos5260-gpio-ctrl2", }, }; @@ -1151,30 +1134,25 @@ struct samsung_pin_ctrl exynos5420_pin_ctrl[] = { .nr_banks = ARRAY_SIZE(exynos5420_pin_banks0), .eint_gpio_init = exynos_eint_gpio_init, .eint_wkup_init = exynos_eint_wkup_init, - .label = "exynos5420-gpio-ctrl0", }, { /* pin-controller instance 1 data */ .pin_banks = exynos5420_pin_banks1, .nr_banks = ARRAY_SIZE(exynos5420_pin_banks1), .eint_gpio_init = exynos_eint_gpio_init, - .label = "exynos5420-gpio-ctrl1", }, { /* pin-controller instance 2 data */ .pin_banks = exynos5420_pin_banks2, .nr_banks = ARRAY_SIZE(exynos5420_pin_banks2), .eint_gpio_init = exynos_eint_gpio_init, - .label = "exynos5420-gpio-ctrl2", }, { /* pin-controller instance 3 data */ .pin_banks = exynos5420_pin_banks3, .nr_banks = ARRAY_SIZE(exynos5420_pin_banks3), .eint_gpio_init = exynos_eint_gpio_init, - .label = "exynos5420-gpio-ctrl3", }, { /* pin-controller instance 4 data */ .pin_banks = exynos5420_pin_banks4, .nr_banks = ARRAY_SIZE(exynos5420_pin_banks4), .eint_gpio_init = exynos_eint_gpio_init, - .label = "exynos5420-gpio-ctrl4", }, }; diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index ad3eaad..e389259 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -578,7 +578,6 @@ struct samsung_pin_ctrl s3c2412_pin_ctrl[] = { .pin_banks = s3c2412_pin_banks, .nr_banks = ARRAY_SIZE(s3c2412_pin_banks), .eint_wkup_init = s3c24xx_eint_init, - .label = "S3C2412-GPIO", }, }; @@ -601,7 +600,6 @@ struct samsung_pin_ctrl s3c2416_pin_ctrl[] = { .pin_banks = s3c2416_pin_banks, .nr_banks = ARRAY_SIZE(s3c2416_pin_banks), .eint_wkup_init = s3c24xx_eint_init, - .label = "S3C2416-GPIO", }, }; @@ -622,7 +620,6 @@ struct samsung_pin_ctrl s3c2440_pin_ctrl[] = { .pin_banks = s3c2440_pin_banks, .nr_banks = ARRAY_SIZE(s3c2440_pin_banks), .eint_wkup_init = s3c24xx_eint_init, - .label = "S3C2440-GPIO", }, }; @@ -646,6 +643,5 @@ struct samsung_pin_ctrl s3c2450_pin_ctrl[] = { .pin_banks = s3c2450_pin_banks, .nr_banks = ARRAY_SIZE(s3c2450_pin_banks), .eint_wkup_init = s3c24xx_eint_init, - .label = "S3C2450-GPIO", }, }; diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index 89143c9..fcf8c36 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -811,6 +811,5 @@ struct samsung_pin_ctrl s3c64xx_pin_ctrl[] = { .nr_banks = ARRAY_SIZE(s3c64xx_pin_banks0), .eint_gpio_init = s3c64xx_eint_gpio_init, .eint_wkup_init = s3c64xx_eint_eint0_init, - .label = "S3C64xx-GPIO", }, }; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index 5cedc9d..da527b39 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -161,7 +161,6 @@ struct samsung_pin_bank { * interrupts for the controller. * @eint_wkup_init: platform specific callback to setup the external wakeup * interrupts for the controller. - * @label: for debug information. */ struct samsung_pin_ctrl { struct samsung_pin_bank *pin_banks; @@ -174,8 +173,6 @@ struct samsung_pin_ctrl { int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *); void (*suspend)(struct samsung_pinctrl_drv_data *); void (*resume)(struct samsung_pinctrl_drv_data *); - - char *label; }; /** -- cgit v1.1 From 94ce944bed8a849a9b83b4e66f0e6e4abc16c457 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Sep 2014 21:05:39 +0200 Subject: pinctrl: samsung: Constify samsung_pin_bank_type struct This structure is not intended to be modified at runtime and functions as constant data shared between multiple pin banks. This patch makes all instances of it constant across the driver. Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-exynos.c | 8 ++++---- drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 6 +++--- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 14 +++++++------- drivers/pinctrl/samsung/pinctrl-samsung.c | 20 +++++++++----------- drivers/pinctrl/samsung/pinctrl-samsung.h | 2 +- 5 files changed, 24 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 7e6463f..0202e00 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -46,12 +46,12 @@ static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip) return container_of(chip, struct exynos_irq_chip, chip); } -static struct samsung_pin_bank_type bank_type_off = { +static const struct samsung_pin_bank_type bank_type_off = { .fld_width = { 4, 1, 2, 2, 2, 2, }, .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, }, }; -static struct samsung_pin_bank_type bank_type_alive = { +static const struct samsung_pin_bank_type bank_type_alive = { .fld_width = { 4, 1, 2, 2, }, .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, }; @@ -171,7 +171,7 @@ static int exynos_irq_request_resources(struct irq_data *irqd) struct irq_chip *chip = irq_data_get_irq_chip(irqd); struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip); struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); - struct samsung_pin_bank_type *bank_type = bank->type; + const struct samsung_pin_bank_type *bank_type = bank->type; struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq; unsigned long reg_con = our_chip->eint_con + bank->eint_offset; @@ -210,7 +210,7 @@ static void exynos_irq_release_resources(struct irq_data *irqd) struct irq_chip *chip = irq_data_get_irq_chip(irqd); struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip); struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); - struct samsung_pin_bank_type *bank_type = bank->type; + const struct samsung_pin_bank_type *bank_type = bank->type; struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq; unsigned long reg_con = our_chip->eint_con + bank->eint_offset; diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index e389259..9db6cf5 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -44,12 +44,12 @@ #define EINT_EDGE_BOTH 6 #define EINT_MASK 0xf -static struct samsung_pin_bank_type bank_type_1bit = { +static const struct samsung_pin_bank_type bank_type_1bit = { .fld_width = { 1, 1, }, .reg_offset = { 0x00, 0x04, }, }; -static struct samsung_pin_bank_type bank_type_2bit = { +static const struct samsung_pin_bank_type bank_type_2bit = { .fld_width = { 2, 1, 2, }, .reg_offset = { 0x00, 0x04, 0x08, }, }; @@ -143,7 +143,7 @@ static void s3c24xx_eint_set_handler(unsigned int irq, unsigned int type) static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d, struct samsung_pin_bank *bank, int pin) { - struct samsung_pin_bank_type *bank_type = bank->type; + const struct samsung_pin_bank_type *bank_type = bank->type; unsigned long flags; void __iomem *reg; u8 shift; diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index fcf8c36..2a14db2 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -68,32 +68,32 @@ #define EINT_CON_MASK 0xF #define EINT_CON_LEN 4 -static struct samsung_pin_bank_type bank_type_4bit_off = { +static const struct samsung_pin_bank_type bank_type_4bit_off = { .fld_width = { 4, 1, 2, 0, 2, 2, }, .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, }, }; -static struct samsung_pin_bank_type bank_type_4bit_alive = { +static const struct samsung_pin_bank_type bank_type_4bit_alive = { .fld_width = { 4, 1, 2, }, .reg_offset = { 0x00, 0x04, 0x08, }, }; -static struct samsung_pin_bank_type bank_type_4bit2_off = { +static const struct samsung_pin_bank_type bank_type_4bit2_off = { .fld_width = { 4, 1, 2, 0, 2, 2, }, .reg_offset = { 0x00, 0x08, 0x0c, 0, 0x10, 0x14, }, }; -static struct samsung_pin_bank_type bank_type_4bit2_alive = { +static const struct samsung_pin_bank_type bank_type_4bit2_alive = { .fld_width = { 4, 1, 2, }, .reg_offset = { 0x00, 0x08, 0x0c, }, }; -static struct samsung_pin_bank_type bank_type_2bit_off = { +static const struct samsung_pin_bank_type bank_type_2bit_off = { .fld_width = { 2, 1, 2, 0, 2, 2, }, .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, }, }; -static struct samsung_pin_bank_type bank_type_2bit_alive = { +static const struct samsung_pin_bank_type bank_type_2bit_alive = { .fld_width = { 2, 1, 2, }, .reg_offset = { 0x00, 0x04, 0x08, }, }; @@ -272,7 +272,7 @@ static void s3c64xx_irq_set_handler(unsigned int irq, unsigned int type) static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d, struct samsung_pin_bank *bank, int pin) { - struct samsung_pin_bank_type *bank_type = bank->type; + const struct samsung_pin_bank_type *bank_type = bank->type; unsigned long flags; void __iomem *reg; u8 shift; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 8ac7503..63a97f1 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -366,7 +366,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, unsigned group, bool enable) { struct samsung_pinctrl_drv_data *drvdata; - struct samsung_pin_bank_type *type; + const struct samsung_pin_bank_type *type; struct samsung_pin_bank *bank; void __iomem *reg; u32 mask, shift, data, pin_offset; @@ -422,7 +422,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *config, bool set) { struct samsung_pinctrl_drv_data *drvdata; - struct samsung_pin_bank_type *type; + const struct samsung_pin_bank_type *type; struct samsung_pin_bank *bank; void __iomem *reg_base; enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); @@ -528,7 +528,7 @@ static const struct pinconf_ops samsung_pinconf_ops = { static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { struct samsung_pin_bank *bank = gc_to_pin_bank(gc); - struct samsung_pin_bank_type *type = bank->type; + const struct samsung_pin_bank_type *type = bank->type; unsigned long flags; void __iomem *reg; u32 data; @@ -552,7 +552,7 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) void __iomem *reg; u32 data; struct samsung_pin_bank *bank = gc_to_pin_bank(gc); - struct samsung_pin_bank_type *type = bank->type; + const struct samsung_pin_bank_type *type = bank->type; reg = bank->drvdata->virt_base + bank->pctl_offset; @@ -569,7 +569,7 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) static int samsung_gpio_set_direction(struct gpio_chip *gc, unsigned offset, bool input) { - struct samsung_pin_bank_type *type; + const struct samsung_pin_bank_type *type; struct samsung_pin_bank *bank; struct samsung_pinctrl_drv_data *drvdata; void __iomem *reg; @@ -1089,9 +1089,8 @@ static void samsung_pinctrl_suspend_dev( for (i = 0; i < ctrl->nr_banks; i++) { struct samsung_pin_bank *bank = &ctrl->pin_banks[i]; void __iomem *reg = virt_base + bank->pctl_offset; - - u8 *offs = bank->type->reg_offset; - u8 *widths = bank->type->fld_width; + const u8 *offs = bank->type->reg_offset; + const u8 *widths = bank->type->fld_width; enum pincfg_type type; /* Registers without a powerdown config aren't lost */ @@ -1140,9 +1139,8 @@ static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata) for (i = 0; i < ctrl->nr_banks; i++) { struct samsung_pin_bank *bank = &ctrl->pin_banks[i]; void __iomem *reg = virt_base + bank->pctl_offset; - - u8 *offs = bank->type->reg_offset; - u8 *widths = bank->type->fld_width; + const u8 *offs = bank->type->reg_offset; + const u8 *widths = bank->type->fld_width; enum pincfg_type type; /* Registers without a powerdown config aren't lost */ diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index da527b39..c677385 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -131,7 +131,7 @@ struct samsung_pin_bank_type { * @pm_save: saved register values during suspend */ struct samsung_pin_bank { - struct samsung_pin_bank_type *type; + const struct samsung_pin_bank_type *type; u32 pctl_offset; u32 pin_base; u8 nr_pins; -- cgit v1.1 From 1bf00d7a6dbff0a29eff4f8c022653b2bc9f5b97 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Sep 2014 21:05:40 +0200 Subject: pinctrl: samsung: Constify samsung_pin_ctrl struct In order to separate initialization constants from runtime data, this patch modifies the driver to store only constant data in samsung_pin_ctrl struct and copy data required at runtime to samsung_pinctrl_drv_data struct. This makes it possible to mark all existing instances of samsung_pin_ctrl struct as const and __initconst. Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-exynos.c | 39 +++++++------- drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 12 ++--- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 14 ++--- drivers/pinctrl/samsung/pinctrl-samsung.c | 87 ++++++++++++++++--------------- drivers/pinctrl/samsung/pinctrl-samsung.h | 40 +++++++------- 5 files changed, 97 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 0202e00..552f7c7 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -277,8 +277,7 @@ static const struct irq_domain_ops exynos_gpio_irqd_ops = { static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) { struct samsung_pinctrl_drv_data *d = data; - struct samsung_pin_ctrl *ctrl = d->ctrl; - struct samsung_pin_bank *bank = ctrl->pin_banks; + struct samsung_pin_bank *bank = d->pin_banks; unsigned int svc, group, pin, virq; svc = readl(d->virt_base + EXYNOS_SVC_OFFSET); @@ -325,8 +324,8 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) return -ENXIO; } - bank = d->ctrl->pin_banks; - for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + bank = d->pin_banks; + for (i = 0; i < d->nr_banks; ++i, ++bank) { if (bank->eint_type != EINT_TYPE_GPIO) continue; bank->irq_domain = irq_domain_add_linear(bank->of_node, @@ -498,8 +497,8 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) if (!wkup_np) return -ENODEV; - bank = d->ctrl->pin_banks; - for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + bank = d->pin_banks; + for (i = 0; i < d->nr_banks; ++i, ++bank) { if (bank->eint_type != EINT_TYPE_WKUP) continue; @@ -556,9 +555,9 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); irq_set_handler_data(irq, muxed_data); - bank = d->ctrl->pin_banks; + bank = d->pin_banks; idx = 0; - for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + for (i = 0; i < d->nr_banks; ++i, ++bank) { if (bank->eint_type != EINT_TYPE_WKUP_MUX) continue; @@ -590,11 +589,10 @@ static void exynos_pinctrl_suspend_bank( static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata) { - struct samsung_pin_ctrl *ctrl = drvdata->ctrl; - struct samsung_pin_bank *bank = ctrl->pin_banks; + struct samsung_pin_bank *bank = drvdata->pin_banks; int i; - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) + for (i = 0; i < drvdata->nr_banks; ++i, ++bank) if (bank->eint_type == EINT_TYPE_GPIO) exynos_pinctrl_suspend_bank(drvdata, bank); } @@ -626,11 +624,10 @@ static void exynos_pinctrl_resume_bank( static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata) { - struct samsung_pin_ctrl *ctrl = drvdata->ctrl; - struct samsung_pin_bank *bank = ctrl->pin_banks; + struct samsung_pin_bank *bank = drvdata->pin_banks; int i; - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) + for (i = 0; i < drvdata->nr_banks; ++i, ++bank) if (bank->eint_type == EINT_TYPE_GPIO) exynos_pinctrl_resume_bank(drvdata, bank); } @@ -673,7 +670,7 @@ static struct samsung_pin_bank s5pv210_pin_bank[] = { EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gph3", 0x0c), }; -struct samsung_pin_ctrl s5pv210_pin_ctrl[] = { +const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = { { /* pin-controller instance 0 data */ .pin_banks = s5pv210_pin_bank, @@ -720,7 +717,7 @@ static struct samsung_pin_bank exynos3250_pin_banks1[] = { * Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes * two gpio/pin-mux/pinconfig controllers. */ -struct samsung_pin_ctrl exynos3250_pin_ctrl[] = { +const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = { { /* pin-controller instance 0 data */ .pin_banks = exynos3250_pin_banks0, @@ -792,7 +789,7 @@ static struct samsung_pin_bank exynos4210_pin_banks2[] = { * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes * three gpio/pin-mux/pinconfig controllers. */ -struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { +const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = { { /* pin-controller instance 0 data */ .pin_banks = exynos4210_pin_banks0, @@ -877,7 +874,7 @@ static struct samsung_pin_bank exynos4x12_pin_banks3[] = { * Samsung pinctrl driver data for Exynos4x12 SoC. Exynos4x12 SoC includes * four gpio/pin-mux/pinconfig controllers. */ -struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { +const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = { { /* pin-controller instance 0 data */ .pin_banks = exynos4x12_pin_banks0, @@ -970,7 +967,7 @@ static struct samsung_pin_bank exynos5250_pin_banks3[] = { * Samsung pinctrl driver data for Exynos5250 SoC. Exynos5250 SoC includes * four gpio/pin-mux/pinconfig controllers. */ -struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { +const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = { { /* pin-controller instance 0 data */ .pin_banks = exynos5250_pin_banks0, @@ -1047,7 +1044,7 @@ static struct samsung_pin_bank exynos5260_pin_banks2[] = { * Samsung pinctrl driver data for Exynos5260 SoC. Exynos5260 SoC includes * three gpio/pin-mux/pinconfig controllers. */ -struct samsung_pin_ctrl exynos5260_pin_ctrl[] = { +const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = { { /* pin-controller instance 0 data */ .pin_banks = exynos5260_pin_banks0, @@ -1127,7 +1124,7 @@ static struct samsung_pin_bank exynos5420_pin_banks4[] = { * Samsung pinctrl driver data for Exynos5420 SoC. Exynos5420 SoC includes * four gpio/pin-mux/pinconfig controllers. */ -struct samsung_pin_ctrl exynos5420_pin_ctrl[] = { +const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = { { /* pin-controller instance 0 data */ .pin_banks = exynos5420_pin_banks0, diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index 9db6cf5..c0c7924 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -518,8 +518,8 @@ static int s3c24xx_eint_init(struct samsung_pinctrl_drv_data *d) irq_set_handler_data(irq, eint_data); } - bank = d->ctrl->pin_banks; - for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + bank = d->pin_banks; + for (i = 0; i < d->nr_banks; ++i, ++bank) { struct s3c24xx_eint_domain_data *ddata; unsigned int mask; unsigned int irq; @@ -573,7 +573,7 @@ static struct samsung_pin_bank s3c2412_pin_banks[] = { PIN_BANK_2BIT(13, 0x080, "gpj"), }; -struct samsung_pin_ctrl s3c2412_pin_ctrl[] = { +const struct samsung_pin_ctrl s3c2412_pin_ctrl[] __initconst = { { .pin_banks = s3c2412_pin_banks, .nr_banks = ARRAY_SIZE(s3c2412_pin_banks), @@ -595,7 +595,7 @@ static struct samsung_pin_bank s3c2416_pin_banks[] = { PIN_BANK_2BIT(2, 0x100, "gpm"), }; -struct samsung_pin_ctrl s3c2416_pin_ctrl[] = { +const struct samsung_pin_ctrl s3c2416_pin_ctrl[] __initconst = { { .pin_banks = s3c2416_pin_banks, .nr_banks = ARRAY_SIZE(s3c2416_pin_banks), @@ -615,7 +615,7 @@ static struct samsung_pin_bank s3c2440_pin_banks[] = { PIN_BANK_2BIT(13, 0x0d0, "gpj"), }; -struct samsung_pin_ctrl s3c2440_pin_ctrl[] = { +const struct samsung_pin_ctrl s3c2440_pin_ctrl[] __initconst = { { .pin_banks = s3c2440_pin_banks, .nr_banks = ARRAY_SIZE(s3c2440_pin_banks), @@ -638,7 +638,7 @@ static struct samsung_pin_bank s3c2450_pin_banks[] = { PIN_BANK_2BIT(2, 0x100, "gpm"), }; -struct samsung_pin_ctrl s3c2450_pin_ctrl[] = { +const struct samsung_pin_ctrl s3c2450_pin_ctrl[] __initconst = { { .pin_banks = s3c2450_pin_banks, .nr_banks = ARRAY_SIZE(s3c2450_pin_banks), diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index 2a14db2..14c3f98 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -468,8 +468,8 @@ static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d) } nr_domains = 0; - bank = d->ctrl->pin_banks; - for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + bank = d->pin_banks; + for (i = 0; i < d->nr_banks; ++i, ++bank) { unsigned int nr_eints; unsigned int mask; @@ -497,9 +497,9 @@ static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d) } data->drvdata = d; - bank = d->ctrl->pin_banks; + bank = d->pin_banks; nr_domains = 0; - for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + for (i = 0; i < d->nr_banks; ++i, ++bank) { if (bank->eint_type != EINT_TYPE_GPIO) continue; @@ -735,8 +735,8 @@ static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d) irq_set_handler_data(irq, data); } - bank = d->ctrl->pin_banks; - for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + bank = d->pin_banks; + for (i = 0; i < d->nr_banks; ++i, ++bank) { struct s3c64xx_eint0_domain_data *ddata; unsigned int nr_eints; unsigned int mask; @@ -804,7 +804,7 @@ static struct samsung_pin_bank s3c64xx_pin_banks0[] = { * Samsung pinctrl driver data for S3C64xx SoC. S3C64xx SoC includes * one gpio/pin-mux/pinconfig controller. */ -struct samsung_pin_ctrl s3c64xx_pin_ctrl[] = { +const struct samsung_pin_ctrl s3c64xx_pin_ctrl[] __initconst = { { /* pin-controller instance 1 data */ .pin_banks = s3c64xx_pin_banks0, diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 63a97f1..6e14811 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -349,7 +349,7 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, { struct samsung_pin_bank *b; - b = drvdata->ctrl->pin_banks; + b = drvdata->pin_banks; while ((pin >= b->pin_base) && ((b->pin_base + b->nr_pins - 1) < pin)) @@ -378,7 +378,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, func = &drvdata->pmx_functions[selector]; grp = &drvdata->pin_groups[group]; - pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->ctrl->base, + pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->pin_base, ®, &pin_offset, &bank); type = bank->type; mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; @@ -431,7 +431,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long flags; drvdata = pinctrl_dev_get_drvdata(pctldev); - pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, + pin_to_reg_bank(drvdata, pin - drvdata->pin_base, ®_base, &pin_offset, &bank); type = bank->type; @@ -834,32 +834,32 @@ static int samsung_pinctrl_register(struct platform_device *pdev, ctrldesc->confops = &samsung_pinconf_ops; pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * - drvdata->ctrl->nr_pins, GFP_KERNEL); + drvdata->nr_pins, GFP_KERNEL); if (!pindesc) { dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); return -ENOMEM; } ctrldesc->pins = pindesc; - ctrldesc->npins = drvdata->ctrl->nr_pins; + ctrldesc->npins = drvdata->nr_pins; /* dynamically populate the pin number and pin name for pindesc */ for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) - pdesc->number = pin + drvdata->ctrl->base; + pdesc->number = pin + drvdata->pin_base; /* * allocate space for storing the dynamically generated names for all * the pins which belong to this pin-controller. */ pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * - drvdata->ctrl->nr_pins, GFP_KERNEL); + drvdata->nr_pins, GFP_KERNEL); if (!pin_names) { dev_err(&pdev->dev, "mem alloc for pin names failed\n"); return -ENOMEM; } /* for each pin, the name of the pin is pin-bank name + pin number */ - for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) { - pin_bank = &drvdata->ctrl->pin_banks[bank]; + for (bank = 0; bank < drvdata->nr_banks; bank++) { + pin_bank = &drvdata->pin_banks[bank]; for (pin = 0; pin < pin_bank->nr_pins; pin++) { sprintf(pin_names, "%s-%d", pin_bank->name, pin); pdesc = pindesc + pin_bank->pin_base + pin; @@ -878,11 +878,11 @@ static int samsung_pinctrl_register(struct platform_device *pdev, return -EINVAL; } - for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) { - pin_bank = &drvdata->ctrl->pin_banks[bank]; + for (bank = 0; bank < drvdata->nr_banks; ++bank) { + pin_bank = &drvdata->pin_banks[bank]; pin_bank->grange.name = pin_bank->name; pin_bank->grange.id = bank; - pin_bank->grange.pin_base = drvdata->ctrl->base + pin_bank->grange.pin_base = drvdata->pin_base + pin_bank->pin_base; pin_bank->grange.base = pin_bank->gpio_chip.base; pin_bank->grange.npins = pin_bank->gpio_chip.ngpio; @@ -918,17 +918,16 @@ static const struct gpio_chip samsung_gpiolib_chip = { static int samsung_gpiolib_register(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { - struct samsung_pin_ctrl *ctrl = drvdata->ctrl; - struct samsung_pin_bank *bank = ctrl->pin_banks; + struct samsung_pin_bank *bank = drvdata->pin_banks; struct gpio_chip *gc; int ret; int i; - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + for (i = 0; i < drvdata->nr_banks; ++i, ++bank) { bank->gpio_chip = samsung_gpiolib_chip; gc = &bank->gpio_chip; - gc->base = ctrl->base + bank->pin_base; + gc->base = drvdata->pin_base + bank->pin_base; gc->ngpio = bank->nr_pins; gc->dev = &pdev->dev; gc->of_node = bank->of_node; @@ -954,27 +953,27 @@ fail: static int samsung_gpiolib_unregister(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { - struct samsung_pin_ctrl *ctrl = drvdata->ctrl; - struct samsung_pin_bank *bank = ctrl->pin_banks; + struct samsung_pin_bank *bank = drvdata->pin_banks; int i; - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) + for (i = 0; i < drvdata->nr_banks; ++i, ++bank) gpiochip_remove(&bank->gpio_chip); + return 0; } static const struct of_device_id samsung_pinctrl_dt_match[]; /* retrieve the soc specific data */ -static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( - struct samsung_pinctrl_drv_data *d, - struct platform_device *pdev) +static const struct samsung_pin_ctrl * +samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, + struct platform_device *pdev) { int id; const struct of_device_id *match; struct device_node *node = pdev->dev.of_node; struct device_node *np; - struct samsung_pin_ctrl *ctrl; + const struct samsung_pin_ctrl *ctrl; struct samsung_pin_bank *bank; int i; @@ -986,19 +985,24 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( match = of_match_node(samsung_pinctrl_dt_match, node); ctrl = (struct samsung_pin_ctrl *)match->data + id; - bank = ctrl->pin_banks; - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + d->suspend = ctrl->suspend; + d->resume = ctrl->resume; + d->pin_banks = ctrl->pin_banks; + d->nr_banks = ctrl->nr_banks; + + bank = d->pin_banks; + for (i = 0; i < d->nr_banks; ++i, ++bank) { spin_lock_init(&bank->slock); bank->drvdata = d; - bank->pin_base = ctrl->nr_pins; - ctrl->nr_pins += bank->nr_pins; + bank->pin_base = d->nr_pins; + d->nr_pins += bank->nr_pins; } for_each_child_of_node(node, np) { if (!of_find_property(np, "gpio-controller", NULL)) continue; - bank = ctrl->pin_banks; - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + bank = d->pin_banks; + for (i = 0; i < d->nr_banks; ++i, ++bank) { if (!strcmp(bank->name, np->name)) { bank->of_node = np; break; @@ -1006,8 +1010,8 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( } } - ctrl->base = pin_base; - pin_base += ctrl->nr_pins; + d->pin_base = pin_base; + pin_base += d->nr_pins; return ctrl; } @@ -1015,8 +1019,8 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( static int samsung_pinctrl_probe(struct platform_device *pdev) { struct samsung_pinctrl_drv_data *drvdata; + const struct samsung_pin_ctrl *ctrl; struct device *dev = &pdev->dev; - struct samsung_pin_ctrl *ctrl; struct resource *res; int ret; @@ -1037,7 +1041,6 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) dev_err(&pdev->dev, "driver data not available\n"); return PTR_ERR(ctrl); } - drvdata->ctrl = ctrl; drvdata->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1082,12 +1085,11 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) static void samsung_pinctrl_suspend_dev( struct samsung_pinctrl_drv_data *drvdata) { - struct samsung_pin_ctrl *ctrl = drvdata->ctrl; void __iomem *virt_base = drvdata->virt_base; int i; - for (i = 0; i < ctrl->nr_banks; i++) { - struct samsung_pin_bank *bank = &ctrl->pin_banks[i]; + for (i = 0; i < drvdata->nr_banks; i++) { + struct samsung_pin_bank *bank = &drvdata->pin_banks[i]; void __iomem *reg = virt_base + bank->pctl_offset; const u8 *offs = bank->type->reg_offset; const u8 *widths = bank->type->fld_width; @@ -1115,8 +1117,8 @@ static void samsung_pinctrl_suspend_dev( } } - if (ctrl->suspend) - ctrl->suspend(drvdata); + if (drvdata->suspend) + drvdata->suspend(drvdata); } /** @@ -1129,15 +1131,14 @@ static void samsung_pinctrl_suspend_dev( */ static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata) { - struct samsung_pin_ctrl *ctrl = drvdata->ctrl; void __iomem *virt_base = drvdata->virt_base; int i; - if (ctrl->resume) - ctrl->resume(drvdata); + if (drvdata->resume) + drvdata->resume(drvdata); - for (i = 0; i < ctrl->nr_banks; i++) { - struct samsung_pin_bank *bank = &ctrl->pin_banks[i]; + for (i = 0; i < drvdata->nr_banks; i++) { + struct samsung_pin_bank *bank = &drvdata->pin_banks[i]; void __iomem *reg = virt_base + bank->pctl_offset; const u8 *offs = bank->type->reg_offset; const u8 *widths = bank->type->fld_width; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index c677385..cf2d61d 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -155,8 +155,6 @@ struct samsung_pin_bank { * struct samsung_pin_ctrl: represent a pin controller. * @pin_banks: list of pin banks included in this controller. * @nr_banks: number of pin banks. - * @base: starting system wide pin number. - * @nr_pins: number of pins supported by the controller. * @eint_gpio_init: platform specific callback to setup the external gpio * interrupts for the controller. * @eint_wkup_init: platform specific callback to setup the external wakeup @@ -166,9 +164,6 @@ struct samsung_pin_ctrl { struct samsung_pin_bank *pin_banks; u32 nr_banks; - u32 base; - u32 nr_pins; - int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *); int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *); void (*suspend)(struct samsung_pinctrl_drv_data *); @@ -188,6 +183,8 @@ struct samsung_pin_ctrl { * @nr_groups: number of such pin groups. * @pmx_functions: list of pin functions available to the driver. * @nr_function: number of such pin functions. + * @pin_base: starting system wide pin number. + * @nr_pins: number of pins supported by the controller. */ struct samsung_pinctrl_drv_data { struct list_head node; @@ -195,7 +192,6 @@ struct samsung_pinctrl_drv_data { struct device *dev; int irq; - struct samsung_pin_ctrl *ctrl; struct pinctrl_desc pctl; struct pinctrl_dev *pctl_dev; @@ -203,6 +199,14 @@ struct samsung_pinctrl_drv_data { unsigned int nr_groups; const struct samsung_pmx_func *pmx_functions; unsigned int nr_functions; + + struct samsung_pin_bank *pin_banks; + u32 nr_banks; + unsigned int pin_base; + unsigned int nr_pins; + + void (*suspend)(struct samsung_pinctrl_drv_data *); + void (*resume)(struct samsung_pinctrl_drv_data *); }; /** @@ -233,17 +237,17 @@ struct samsung_pmx_func { }; /* list of all exported SoC specific data */ -extern struct samsung_pin_ctrl exynos3250_pin_ctrl[]; -extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; -extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; -extern struct samsung_pin_ctrl exynos5250_pin_ctrl[]; -extern struct samsung_pin_ctrl exynos5260_pin_ctrl[]; -extern struct samsung_pin_ctrl exynos5420_pin_ctrl[]; -extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[]; -extern struct samsung_pin_ctrl s3c2412_pin_ctrl[]; -extern struct samsung_pin_ctrl s3c2416_pin_ctrl[]; -extern struct samsung_pin_ctrl s3c2440_pin_ctrl[]; -extern struct samsung_pin_ctrl s3c2450_pin_ctrl[]; -extern struct samsung_pin_ctrl s5pv210_pin_ctrl[]; +extern const struct samsung_pin_ctrl exynos3250_pin_ctrl[]; +extern const struct samsung_pin_ctrl exynos4210_pin_ctrl[]; +extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; +extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[]; +extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[]; +extern const struct samsung_pin_ctrl exynos5420_pin_ctrl[]; +extern const struct samsung_pin_ctrl s3c64xx_pin_ctrl[]; +extern const struct samsung_pin_ctrl s3c2412_pin_ctrl[]; +extern const struct samsung_pin_ctrl s3c2416_pin_ctrl[]; +extern const struct samsung_pin_ctrl s3c2440_pin_ctrl[]; +extern const struct samsung_pin_ctrl s3c2450_pin_ctrl[]; +extern const struct samsung_pin_ctrl s5pv210_pin_ctrl[]; #endif /* __PINCTRL_SAMSUNG_H */ -- cgit v1.1 From 8100cf47698fedbde6dc3fa540b1fefcee69fd40 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Sep 2014 21:05:41 +0200 Subject: pinctrl: samsung: Separate per-bank init and runtime data Currently the driver mixes constant init data with runtime data, which is far from being elegant and can invite potential hard to track issues. This patch intends to solve this by introducing a new samsung_pin_bank_data structure to hold only constant data known at compile time, which can be copied to main samsung_pin_bank struct used at runtime. In addition, thanks to this change, all per-bank initdata can be marked with const and __initconst keywords and dropped after init completes. Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-exynos.c | 44 +++++++++++++++---------------- drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 8 +++--- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 2 +- drivers/pinctrl/samsung/pinctrl-samsung.c | 18 +++++++++++-- drivers/pinctrl/samsung/pinctrl-samsung.h | 33 ++++++++++++++++++++--- 5 files changed, 72 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 552f7c7..b4490cb 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -633,7 +633,7 @@ static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata) } /* pin banks of s5pv210 pin-controller */ -static struct samsung_pin_bank s5pv210_pin_bank[] = { +static const struct samsung_pin_bank_data s5pv210_pin_bank[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpa1", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), @@ -683,7 +683,7 @@ const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = { }; /* pin banks of exynos3250 pin-controller 0 */ -static struct samsung_pin_bank exynos3250_pin_banks0[] = { +static const struct samsung_pin_bank_data exynos3250_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), @@ -694,7 +694,7 @@ static struct samsung_pin_bank exynos3250_pin_banks0[] = { }; /* pin banks of exynos3250 pin-controller 1 */ -static struct samsung_pin_bank exynos3250_pin_banks1[] = { +static const struct samsung_pin_bank_data exynos3250_pin_banks1[] __initconst = { EXYNOS_PIN_BANK_EINTN(8, 0x120, "gpe0"), EXYNOS_PIN_BANK_EINTN(8, 0x140, "gpe1"), EXYNOS_PIN_BANK_EINTN(3, 0x180, "gpe2"), @@ -737,7 +737,7 @@ const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = { }; /* pin banks of exynos4210 pin-controller 0 */ -static struct samsung_pin_bank exynos4210_pin_banks0[] = { +static const struct samsung_pin_bank_data exynos4210_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), @@ -757,7 +757,7 @@ static struct samsung_pin_bank exynos4210_pin_banks0[] = { }; /* pin banks of exynos4210 pin-controller 1 */ -static struct samsung_pin_bank exynos4210_pin_banks1[] = { +static const struct samsung_pin_bank_data exynos4210_pin_banks1[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0", 0x00), EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1", 0x04), EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08), @@ -781,7 +781,7 @@ static struct samsung_pin_bank exynos4210_pin_banks1[] = { }; /* pin banks of exynos4210 pin-controller 2 */ -static struct samsung_pin_bank exynos4210_pin_banks2[] = { +static const struct samsung_pin_bank_data exynos4210_pin_banks2[] __initconst = { EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"), }; @@ -813,7 +813,7 @@ const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = { }; /* pin banks of exynos4x12 pin-controller 0 */ -static struct samsung_pin_bank exynos4x12_pin_banks0[] = { +static const struct samsung_pin_bank_data exynos4x12_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), @@ -830,7 +830,7 @@ static struct samsung_pin_bank exynos4x12_pin_banks0[] = { }; /* pin banks of exynos4x12 pin-controller 1 */ -static struct samsung_pin_bank exynos4x12_pin_banks1[] = { +static const struct samsung_pin_bank_data exynos4x12_pin_banks1[] __initconst = { EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08), EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c), EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10), @@ -857,12 +857,12 @@ static struct samsung_pin_bank exynos4x12_pin_banks1[] = { }; /* pin banks of exynos4x12 pin-controller 2 */ -static struct samsung_pin_bank exynos4x12_pin_banks2[] = { +static const struct samsung_pin_bank_data exynos4x12_pin_banks2[] __initconst = { EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00), }; /* pin banks of exynos4x12 pin-controller 3 */ -static struct samsung_pin_bank exynos4x12_pin_banks3[] = { +static const struct samsung_pin_bank_data exynos4x12_pin_banks3[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00), EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpv2", 0x08), @@ -908,7 +908,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = { }; /* pin banks of exynos5250 pin-controller 0 */ -static struct samsung_pin_bank exynos5250_pin_banks0[] = { +static const struct samsung_pin_bank_data exynos5250_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08), @@ -937,7 +937,7 @@ static struct samsung_pin_bank exynos5250_pin_banks0[] = { }; /* pin banks of exynos5250 pin-controller 1 */ -static struct samsung_pin_bank exynos5250_pin_banks1[] = { +static const struct samsung_pin_bank_data exynos5250_pin_banks1[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00), EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04), EXYNOS_PIN_BANK_EINTG(4, 0x040, "gpf0", 0x08), @@ -950,7 +950,7 @@ static struct samsung_pin_bank exynos5250_pin_banks1[] = { }; /* pin banks of exynos5250 pin-controller 2 */ -static struct samsung_pin_bank exynos5250_pin_banks2[] = { +static const struct samsung_pin_bank_data exynos5250_pin_banks2[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00), EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv2", 0x08), @@ -959,7 +959,7 @@ static struct samsung_pin_bank exynos5250_pin_banks2[] = { }; /* pin banks of exynos5250 pin-controller 3 */ -static struct samsung_pin_bank exynos5250_pin_banks3[] = { +static const struct samsung_pin_bank_data exynos5250_pin_banks3[] __initconst = { EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00), }; @@ -1001,7 +1001,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = { }; /* pin banks of exynos5260 pin-controller 0 */ -static struct samsung_pin_bank exynos5260_pin_banks0[] = { +static const struct samsung_pin_bank_data exynos5260_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpa0", 0x00), EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpa1", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08), @@ -1026,7 +1026,7 @@ static struct samsung_pin_bank exynos5260_pin_banks0[] = { }; /* pin banks of exynos5260 pin-controller 1 */ -static struct samsung_pin_bank exynos5260_pin_banks1[] = { +static const struct samsung_pin_bank_data exynos5260_pin_banks1[] __initconst = { EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpc0", 0x00), EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpc1", 0x04), EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08), @@ -1035,7 +1035,7 @@ static struct samsung_pin_bank exynos5260_pin_banks1[] = { }; /* pin banks of exynos5260 pin-controller 2 */ -static struct samsung_pin_bank exynos5260_pin_banks2[] = { +static const struct samsung_pin_bank_data exynos5260_pin_banks2[] __initconst = { EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00), EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04), }; @@ -1065,7 +1065,7 @@ const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = { }; /* pin banks of exynos5420 pin-controller 0 */ -static struct samsung_pin_bank exynos5420_pin_banks0[] = { +static const struct samsung_pin_bank_data exynos5420_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00), EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00), EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04), @@ -1074,7 +1074,7 @@ static struct samsung_pin_bank exynos5420_pin_banks0[] = { }; /* pin banks of exynos5420 pin-controller 1 */ -static struct samsung_pin_bank exynos5420_pin_banks1[] = { +static const struct samsung_pin_bank_data exynos5420_pin_banks1[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpc0", 0x00), EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpc1", 0x04), EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08), @@ -1091,7 +1091,7 @@ static struct samsung_pin_bank exynos5420_pin_banks1[] = { }; /* pin banks of exynos5420 pin-controller 2 */ -static struct samsung_pin_bank exynos5420_pin_banks2[] = { +static const struct samsung_pin_bank_data exynos5420_pin_banks2[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00), EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04), EXYNOS_PIN_BANK_EINTG(6, 0x040, "gpf0", 0x08), @@ -1103,7 +1103,7 @@ static struct samsung_pin_bank exynos5420_pin_banks2[] = { }; /* pin banks of exynos5420 pin-controller 3 */ -static struct samsung_pin_bank exynos5420_pin_banks3[] = { +static const struct samsung_pin_bank_data exynos5420_pin_banks3[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08), @@ -1116,7 +1116,7 @@ static struct samsung_pin_bank exynos5420_pin_banks3[] = { }; /* pin banks of exynos5420 pin-controller 4 */ -static struct samsung_pin_bank exynos5420_pin_banks4[] = { +static const struct samsung_pin_bank_data exynos5420_pin_banks4[] __initconst = { EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00), }; diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index c0c7924..f1993f42 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -561,7 +561,7 @@ static int s3c24xx_eint_init(struct samsung_pinctrl_drv_data *d) return 0; } -static struct samsung_pin_bank s3c2412_pin_banks[] = { +static const struct samsung_pin_bank_data s3c2412_pin_banks[] __initconst = { PIN_BANK_A(23, 0x000, "gpa"), PIN_BANK_2BIT(11, 0x010, "gpb"), PIN_BANK_2BIT(16, 0x020, "gpc"), @@ -581,7 +581,7 @@ const struct samsung_pin_ctrl s3c2412_pin_ctrl[] __initconst = { }, }; -static struct samsung_pin_bank s3c2416_pin_banks[] = { +static const struct samsung_pin_bank_data s3c2416_pin_banks[] __initconst = { PIN_BANK_A(27, 0x000, "gpa"), PIN_BANK_2BIT(11, 0x010, "gpb"), PIN_BANK_2BIT(16, 0x020, "gpc"), @@ -603,7 +603,7 @@ const struct samsung_pin_ctrl s3c2416_pin_ctrl[] __initconst = { }, }; -static struct samsung_pin_bank s3c2440_pin_banks[] = { +static const struct samsung_pin_bank_data s3c2440_pin_banks[] __initconst = { PIN_BANK_A(25, 0x000, "gpa"), PIN_BANK_2BIT(11, 0x010, "gpb"), PIN_BANK_2BIT(16, 0x020, "gpc"), @@ -623,7 +623,7 @@ const struct samsung_pin_ctrl s3c2440_pin_ctrl[] __initconst = { }, }; -static struct samsung_pin_bank s3c2450_pin_banks[] = { +static const struct samsung_pin_bank_data s3c2450_pin_banks[] __initconst = { PIN_BANK_A(28, 0x000, "gpa"), PIN_BANK_2BIT(11, 0x010, "gpb"), PIN_BANK_2BIT(16, 0x020, "gpc"), diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index 14c3f98..7756c1e 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -780,7 +780,7 @@ static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d) } /* pin banks of s3c64xx pin-controller 0 */ -static struct samsung_pin_bank s3c64xx_pin_banks0[] = { +static const struct samsung_pin_bank_data s3c64xx_pin_banks0[] __initconst = { PIN_BANK_4BIT_EINTG(8, 0x000, "gpa", 0), PIN_BANK_4BIT_EINTG(7, 0x020, "gpb", 8), PIN_BANK_4BIT_EINTG(8, 0x040, "gpc", 16), diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 6e14811..96ef6e5 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -973,6 +973,7 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, const struct of_device_id *match; struct device_node *node = pdev->dev.of_node; struct device_node *np; + const struct samsung_pin_bank_data *bdata; const struct samsung_pin_ctrl *ctrl; struct samsung_pin_bank *bank; int i; @@ -987,11 +988,24 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, d->suspend = ctrl->suspend; d->resume = ctrl->resume; - d->pin_banks = ctrl->pin_banks; d->nr_banks = ctrl->nr_banks; + d->pin_banks = devm_kcalloc(&pdev->dev, d->nr_banks, + sizeof(*d->pin_banks), GFP_KERNEL); + if (!d->pin_banks) + return ERR_PTR(-ENOMEM); bank = d->pin_banks; - for (i = 0; i < d->nr_banks; ++i, ++bank) { + bdata = ctrl->pin_banks; + for (i = 0; i < ctrl->nr_banks; ++i, ++bdata, ++bank) { + bank->type = bdata->type; + bank->pctl_offset = bdata->pctl_offset; + bank->nr_pins = bdata->nr_pins; + bank->eint_func = bdata->eint_func; + bank->eint_type = bdata->eint_type; + bank->eint_mask = bdata->eint_mask; + bank->eint_offset = bdata->eint_offset; + bank->name = bdata->name; + spin_lock_init(&bank->slock); bank->drvdata = d; bank->pin_base = d->nr_pins; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index cf2d61d..ec43b7d 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -113,15 +113,39 @@ struct samsung_pin_bank_type { }; /** + * struct samsung_pin_bank_data: represent a controller pin-bank (init data). + * @type: type of the bank (register offsets and bitfield widths) + * @pctl_offset: starting offset of the pin-bank registers. + * @nr_pins: number of pins included in this bank. + * @eint_func: function to set in CON register to configure pin as EINT. + * @eint_type: type of the external interrupt supported by the bank. + * @eint_mask: bit mask of pins which support EINT function. + * @eint_offset: SoC-specific EINT register or interrupt offset of bank. + * @name: name to be prefixed for each pin in this pin bank. + */ +struct samsung_pin_bank_data { + const struct samsung_pin_bank_type *type; + u32 pctl_offset; + u8 nr_pins; + u8 eint_func; + enum eint_type eint_type; + u32 eint_mask; + u32 eint_offset; + const char *name; +}; + +/** * struct samsung_pin_bank: represent a controller pin-bank. * @type: type of the bank (register offsets and bitfield widths) * @pctl_offset: starting offset of the pin-bank registers. - * @pin_base: starting pin number of the bank. * @nr_pins: number of pins included in this bank. * @eint_func: function to set in CON register to configure pin as EINT. * @eint_type: type of the external interrupt supported by the bank. * @eint_mask: bit mask of pins which support EINT function. + * @eint_offset: SoC-specific EINT register or interrupt offset of bank. * @name: name to be prefixed for each pin in this pin bank. + * @pin_base: starting pin number of the bank. + * @soc_priv: per-bank private data for SoC-specific code. * @of_node: OF node of the bank. * @drvdata: link to controller driver data * @irq_domain: IRQ domain of the bank. @@ -133,13 +157,14 @@ struct samsung_pin_bank_type { struct samsung_pin_bank { const struct samsung_pin_bank_type *type; u32 pctl_offset; - u32 pin_base; u8 nr_pins; u8 eint_func; enum eint_type eint_type; u32 eint_mask; u32 eint_offset; - char *name; + const char *name; + + u32 pin_base; void *soc_priv; struct device_node *of_node; struct samsung_pinctrl_drv_data *drvdata; @@ -161,7 +186,7 @@ struct samsung_pin_bank { * interrupts for the controller. */ struct samsung_pin_ctrl { - struct samsung_pin_bank *pin_banks; + const struct samsung_pin_bank_data *pin_banks; u32 nr_banks; int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *); -- cgit v1.1 From 0d3d30db93635936652417efd0f4a3e9049d0938 Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 9 Oct 2014 19:24:29 +0530 Subject: pinctrl: exynos: Generalize the eint16_31 demux code The function exynos_irq_demux_eint16_31 uses pre-defined offsets for external interrupt pending status and mask registers. So this function is not extensible for Exynos7 SoC which has these registers at different offsets. Generalize the exynos_irq_demux_eint16_31 function by using the pending/mask register offset values from the exynos_irq_chip structure. This is done by adding a irq_chip field to the samsung_pin_bank struct. Signed-off-by: Abhilash Kesavan Reviewed-by: Thomas Abraham Tested-by: Thomas Abraham Acked-by: Tomasz Figa Cc: Linus Walleij Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-exynos.c | 14 ++++++++++---- drivers/pinctrl/samsung/pinctrl-samsung.h | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index b4490cb..954e555 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -260,7 +260,7 @@ static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, struct samsung_pin_bank *b = h->host_data; irq_set_chip_data(virq, b); - irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip.chip, + irq_set_chip_and_handler(virq, &b->irq_chip->chip, handle_level_irq); set_irq_flags(virq, IRQF_VALID); return 0; @@ -343,6 +343,8 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) ret = -ENOMEM; goto err_domains; } + + bank->irq_chip = &exynos_gpio_irq_chip; } return 0; @@ -444,9 +446,9 @@ static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) for (i = 0; i < eintd->nr_banks; ++i) { struct samsung_pin_bank *b = eintd->banks[i]; - pend = readl(d->virt_base + EXYNOS_WKUP_EPEND_OFFSET + pend = readl(d->virt_base + b->irq_chip->eint_pend + b->eint_offset); - mask = readl(d->virt_base + EXYNOS_WKUP_EMASK_OFFSET + mask = readl(d->virt_base + b->irq_chip->eint_mask + b->eint_offset); exynos_irq_demux_eint(pend & ~mask, b->irq_domain); } @@ -457,7 +459,9 @@ static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) static int exynos_wkup_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, &exynos_wkup_irq_chip.chip, + struct samsung_pin_bank *b = h->host_data; + + irq_set_chip_and_handler(virq, &b->irq_chip->chip, handle_level_irq); irq_set_chip_data(virq, h->host_data); set_irq_flags(virq, IRQF_VALID); @@ -509,6 +513,8 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) return -ENXIO; } + bank->irq_chip = &exynos_wkup_irq_chip; + if (!of_find_property(bank->of_node, "interrupts", NULL)) { bank->eint_type = EINT_TYPE_WKUP_MUX; ++muxed_banks; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index ec43b7d..3076b8b 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -151,6 +151,7 @@ struct samsung_pin_bank_data { * @irq_domain: IRQ domain of the bank. * @gpio_chip: GPIO chip of the bank. * @grange: linux gpio pin range supported by this bank. + * @irq_chip: link to irq chip for external gpio and wakeup interrupts. * @slock: spinlock protecting bank registers * @pm_save: saved register values during suspend */ @@ -171,6 +172,7 @@ struct samsung_pin_bank { struct irq_domain *irq_domain; struct gpio_chip gpio_chip; struct pinctrl_gpio_range grange; + struct exynos_irq_chip *irq_chip; spinlock_t slock; u32 pm_save[PINCFG_TYPE_NUM + 1]; /* +1 to handle double CON registers*/ -- cgit v1.1 From 6f5e41bd8fc6d34bc9a2aabe75b5f67b6f99cda9 Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 9 Oct 2014 19:24:30 +0530 Subject: pinctrl: exynos: Consolidate irq domain callbacks Adding a irq_chip field to the samsung_pin_bank struct helps in consolidating the irq domain callbacks for external gpio and wakeup interrupt controllers. The exynos_wkup_irqd_ops and exynos_gpio_irqd_ops have now been merged into a single exynos_eint_irqd_ops. Signed-off-by: Abhilash Kesavan Reviewed-by: Thomas Abraham Tested-by: Thomas Abraham Acked-by: Tomasz Figa Cc: Linus Walleij Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-exynos.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 954e555..7a7eb6a 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -254,7 +254,7 @@ static struct exynos_irq_chip exynos_gpio_irq_chip = { .eint_pend = EXYNOS_GPIO_EPEND_OFFSET, }; -static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, +static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct samsung_pin_bank *b = h->host_data; @@ -267,10 +267,10 @@ static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, } /* - * irq domain callbacks for external gpio interrupt controller. + * irq domain callbacks for external gpio and wakeup interrupt controllers. */ -static const struct irq_domain_ops exynos_gpio_irqd_ops = { - .map = exynos_gpio_irq_map, +static const struct irq_domain_ops exynos_eint_irqd_ops = { + .map = exynos_eint_irq_map, .xlate = irq_domain_xlate_twocell, }; @@ -329,7 +329,7 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) if (bank->eint_type != EINT_TYPE_GPIO) continue; bank->irq_domain = irq_domain_add_linear(bank->of_node, - bank->nr_pins, &exynos_gpio_irqd_ops, bank); + bank->nr_pins, &exynos_eint_irqd_ops, bank); if (!bank->irq_domain) { dev_err(dev, "gpio irq domain add failed\n"); ret = -ENXIO; @@ -456,26 +456,6 @@ static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int exynos_wkup_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct samsung_pin_bank *b = h->host_data; - - irq_set_chip_and_handler(virq, &b->irq_chip->chip, - handle_level_irq); - irq_set_chip_data(virq, h->host_data); - set_irq_flags(virq, IRQF_VALID); - return 0; -} - -/* - * irq domain callbacks for external wakeup interrupt controller. - */ -static const struct irq_domain_ops exynos_wkup_irqd_ops = { - .map = exynos_wkup_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - /* * exynos_eint_wkup_init() - setup handling of external wakeup interrupts. * @d: driver data of samsung pinctrl driver. @@ -507,7 +487,7 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) continue; bank->irq_domain = irq_domain_add_linear(bank->of_node, - bank->nr_pins, &exynos_wkup_irqd_ops, bank); + bank->nr_pins, &exynos_eint_irqd_ops, bank); if (!bank->irq_domain) { dev_err(dev, "wkup irq domain add failed\n"); return -ENXIO; -- cgit v1.1 From 14c255d35b25126149fb2fd199b030404229af65 Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 9 Oct 2014 19:24:31 +0530 Subject: pinctrl: exynos: Add irq_chip instance for Exynos7 wakeup interrupts Exynos7 uses different offsets for wakeup interrupt configuration registers. So a new irq_chip instance for Exynos7 wakeup interrupts is added. The irq_chip selection is now based on the wakeup interrupt controller compatible string. Signed-off-by: Abhilash Kesavan Reviewed-by: Thomas Abraham Tested-by: Thomas Abraham Acked-by: Tomasz Figa Cc: Linus Walleij Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-exynos.c | 45 +++++++++++++++++++++++++------- drivers/pinctrl/samsung/pinctrl-exynos.h | 3 +++ 2 files changed, 38 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 7a7eb6a..d97765c 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -56,12 +56,6 @@ static const struct samsung_pin_bank_type bank_type_alive = { .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, }; -/* list of external wakeup controllers supported */ -static const struct of_device_id exynos_wkup_irq_ids[] = { - { .compatible = "samsung,exynos4210-wakeup-eint", }, - { } -}; - static void exynos_irq_mask(struct irq_data *irqd) { struct irq_chip *chip = irq_data_get_irq_chip(irqd); @@ -384,9 +378,9 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on) /* * irq_chip for wakeup interrupts */ -static struct exynos_irq_chip exynos_wkup_irq_chip = { +static struct exynos_irq_chip exynos4210_wkup_irq_chip __initdata = { .chip = { - .name = "exynos_wkup_irq_chip", + .name = "exynos4210_wkup_irq_chip", .irq_unmask = exynos_irq_unmask, .irq_mask = exynos_irq_mask, .irq_ack = exynos_irq_ack, @@ -400,6 +394,31 @@ static struct exynos_irq_chip exynos_wkup_irq_chip = { .eint_pend = EXYNOS_WKUP_EPEND_OFFSET, }; +static struct exynos_irq_chip exynos7_wkup_irq_chip __initdata = { + .chip = { + .name = "exynos7_wkup_irq_chip", + .irq_unmask = exynos_irq_unmask, + .irq_mask = exynos_irq_mask, + .irq_ack = exynos_irq_ack, + .irq_set_type = exynos_irq_set_type, + .irq_set_wake = exynos_wkup_irq_set_wake, + .irq_request_resources = exynos_irq_request_resources, + .irq_release_resources = exynos_irq_release_resources, + }, + .eint_con = EXYNOS7_WKUP_ECON_OFFSET, + .eint_mask = EXYNOS7_WKUP_EMASK_OFFSET, + .eint_pend = EXYNOS7_WKUP_EPEND_OFFSET, +}; + +/* list of external wakeup controllers supported */ +static const struct of_device_id exynos_wkup_irq_ids[] = { + { .compatible = "samsung,exynos4210-wakeup-eint", + .data = &exynos4210_wkup_irq_chip }, + { .compatible = "samsung,exynos7-wakeup-eint", + .data = &exynos7_wkup_irq_chip }, + { } +}; + /* interrupt handler for wakeup interrupts 0..15 */ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) { @@ -468,12 +487,18 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) struct samsung_pin_bank *bank; struct exynos_weint_data *weint_data; struct exynos_muxed_weint_data *muxed_data; + struct exynos_irq_chip *irq_chip; unsigned int muxed_banks = 0; unsigned int i; int idx, irq; for_each_child_of_node(dev->of_node, np) { - if (of_match_node(exynos_wkup_irq_ids, np)) { + const struct of_device_id *match; + + match = of_match_node(exynos_wkup_irq_ids, np); + if (match) { + irq_chip = kmemdup(match->data, + sizeof(*irq_chip), GFP_KERNEL); wkup_np = np; break; } @@ -493,7 +518,7 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) return -ENXIO; } - bank->irq_chip = &exynos_wkup_irq_chip; + bank->irq_chip = irq_chip; if (!of_find_property(bank->of_node, "interrupts", NULL)) { bank->eint_type = EINT_TYPE_WKUP_MUX; diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index 3c91c35..0f0f7ce 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -25,6 +25,9 @@ #define EXYNOS_WKUP_ECON_OFFSET 0xE00 #define EXYNOS_WKUP_EMASK_OFFSET 0xF00 #define EXYNOS_WKUP_EPEND_OFFSET 0xF40 +#define EXYNOS7_WKUP_ECON_OFFSET 0x700 +#define EXYNOS7_WKUP_EMASK_OFFSET 0x900 +#define EXYNOS7_WKUP_EPEND_OFFSET 0xA00 #define EXYNOS_SVC_OFFSET 0xB08 #define EXYNOS_EINT_FUNC 0xF -- cgit v1.1 From 50cea0cff7131b364c0ff80dedf8e91212b18a26 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Ch Date: Thu, 9 Oct 2014 19:24:32 +0530 Subject: pinctrl: exynos: Add initial driver data for Exynos7 This patch adds initial driver data for Exynos7 pinctrl support. Signed-off-by: Naveen Krishna Ch Signed-off-by: Abhilash Kesavan Reviewed-by: Thomas Abraham Tested-by: Thomas Abraham Acked-by: Tomasz Figa Cc: Linus Walleij Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-exynos.c | 105 ++++++++++++++++++++++++++++++ drivers/pinctrl/samsung/pinctrl-samsung.c | 2 + drivers/pinctrl/samsung/pinctrl-samsung.h | 1 + 3 files changed, 108 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index d97765c..5622d8a 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -1164,3 +1164,108 @@ const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = { .eint_gpio_init = exynos_eint_gpio_init, }, }; + +/* pin banks of exynos7 pin-controller - ALIVE */ +static const struct samsung_pin_bank_data exynos7_pin_banks0[] __initconst = { + EXYNOS_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00), + EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04), + EXYNOS_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08), + EXYNOS_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c), +}; + +/* pin banks of exynos7 pin-controller - BUS0 */ +static const struct samsung_pin_bank_data exynos7_pin_banks1[] __initconst = { + EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00), + EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpc0", 0x04), + EXYNOS_PIN_BANK_EINTG(2, 0x040, "gpc1", 0x08), + EXYNOS_PIN_BANK_EINTG(6, 0x060, "gpc2", 0x0c), + EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpc3", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpd0", 0x14), + EXYNOS_PIN_BANK_EINTG(6, 0x0c0, "gpd1", 0x18), + EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpd2", 0x1c), + EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpd4", 0x20), + EXYNOS_PIN_BANK_EINTG(4, 0x120, "gpd5", 0x24), + EXYNOS_PIN_BANK_EINTG(6, 0x140, "gpd6", 0x28), + EXYNOS_PIN_BANK_EINTG(3, 0x160, "gpd7", 0x2c), + EXYNOS_PIN_BANK_EINTG(2, 0x180, "gpd8", 0x30), + EXYNOS_PIN_BANK_EINTG(2, 0x1a0, "gpg0", 0x34), + EXYNOS_PIN_BANK_EINTG(4, 0x1c0, "gpg3", 0x38), +}; + +/* pin banks of exynos7 pin-controller - NFC */ +static const struct samsung_pin_bank_data exynos7_pin_banks2[] __initconst = { + EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj0", 0x00), +}; + +/* pin banks of exynos7 pin-controller - TOUCH */ +static const struct samsung_pin_bank_data exynos7_pin_banks3[] __initconst = { + EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj1", 0x00), +}; + +/* pin banks of exynos7 pin-controller - FF */ +static const struct samsung_pin_bank_data exynos7_pin_banks4[] __initconst = { + EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpg4", 0x00), +}; + +/* pin banks of exynos7 pin-controller - ESE */ +static const struct samsung_pin_bank_data exynos7_pin_banks5[] __initconst = { + EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpv7", 0x00), +}; + +/* pin banks of exynos7 pin-controller - FSYS0 */ +static const struct samsung_pin_bank_data exynos7_pin_banks6[] __initconst = { + EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpr4", 0x00), +}; + +/* pin banks of exynos7 pin-controller - FSYS1 */ +static const struct samsung_pin_bank_data exynos7_pin_banks7[] __initconst = { + EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpr0", 0x00), + EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpr1", 0x04), + EXYNOS_PIN_BANK_EINTG(5, 0x040, "gpr2", 0x08), + EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpr3", 0x0c), +}; + +const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = { + { + /* pin-controller instance 0 Alive data */ + .pin_banks = exynos7_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks0), + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + }, { + /* pin-controller instance 1 BUS0 data */ + .pin_banks = exynos7_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks1), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 2 NFC data */ + .pin_banks = exynos7_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 3 TOUCH data */ + .pin_banks = exynos7_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks3), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 4 FF data */ + .pin_banks = exynos7_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 5 ESE data */ + .pin_banks = exynos7_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 6 FSYS0 data */ + .pin_banks = exynos7_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks6), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 7 FSYS1 data */ + .pin_banks = exynos7_pin_banks7, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks7), + .eint_gpio_init = exynos_eint_gpio_init, + }, +}; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 96ef6e5..e5a8150 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1239,6 +1239,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { .data = (void *)exynos5420_pin_ctrl }, { .compatible = "samsung,s5pv210-pinctrl", .data = (void *)s5pv210_pin_ctrl }, + { .compatible = "samsung,exynos7-pinctrl", + .data = (void *)exynos7_pin_ctrl }, #endif #ifdef CONFIG_PINCTRL_S3C64XX { .compatible = "samsung,s3c64xx-pinctrl", diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index 3076b8b..29004be 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -270,6 +270,7 @@ extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5420_pin_ctrl[]; +extern const struct samsung_pin_ctrl exynos7_pin_ctrl[]; extern const struct samsung_pin_ctrl s3c64xx_pin_ctrl[]; extern const struct samsung_pin_ctrl s3c2412_pin_ctrl[]; extern const struct samsung_pin_ctrl s3c2416_pin_ctrl[]; -- cgit v1.1 From 2891ba2906b6d2fd453042f410a11e6fc3edc37d Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Mon, 27 Oct 2014 10:21:18 +0900 Subject: pinctrl: exynos: Add support for Exynos4415 The pin controllers of Exynos4415 are similar to Exynos4412, but certain differences cause the need to create separate driver data for it. This patch adds pin controller and bank descriptor arrays to the driver to support the new SoC. Cc: Tomasz Figa Cc: Thomas Abraham Cc: Linus Walleij Signed-off-by: Tomasz Figa [cw00.choi: Rebase it on mainline kernel] Signed-off-by: Chanwoo Choi Acked-by: Kyungmin Park [tomasz.figa@gmail.com: Resolved merge with earlier clean-up series.] Signed-off-by: Tomasz Figa --- drivers/pinctrl/samsung/pinctrl-exynos.c | 75 +++++++++++++++++++++++++++++++ drivers/pinctrl/samsung/pinctrl-samsung.c | 2 + drivers/pinctrl/samsung/pinctrl-samsung.h | 1 + 3 files changed, 78 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 5622d8a..d5d4cfc 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -918,6 +918,81 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = { }, }; +/* pin banks of exynos4415 pin-controller 0 */ +static const struct samsung_pin_bank_data exynos4415_pin_banks0[] = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), + EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), + EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c), + EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14), + EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18), + EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30), + EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34), + EXYNOS_PIN_BANK_EINTG(1, 0x1C0, "gpf2", 0x38), +}; + +/* pin banks of exynos4415 pin-controller 1 */ +static const struct samsung_pin_bank_data exynos4415_pin_banks1[] = { + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpk0", 0x08), + EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c), + EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10), + EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14), + EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpl0", 0x18), + EXYNOS_PIN_BANK_EINTN(6, 0x120, "mp00"), + EXYNOS_PIN_BANK_EINTN(4, 0x140, "mp01"), + EXYNOS_PIN_BANK_EINTN(6, 0x160, "mp02"), + EXYNOS_PIN_BANK_EINTN(8, 0x180, "mp03"), + EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "mp04"), + EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "mp05"), + EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "mp06"), + EXYNOS_PIN_BANK_EINTG(8, 0x260, "gpm0", 0x24), + EXYNOS_PIN_BANK_EINTG(7, 0x280, "gpm1", 0x28), + EXYNOS_PIN_BANK_EINTG(5, 0x2A0, "gpm2", 0x2c), + EXYNOS_PIN_BANK_EINTG(8, 0x2C0, "gpm3", 0x30), + EXYNOS_PIN_BANK_EINTG(8, 0x2E0, "gpm4", 0x34), + EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00), + EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04), + EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08), + EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c), +}; + +/* pin banks of exynos4415 pin-controller 2 */ +static const struct samsung_pin_bank_data exynos4415_pin_banks2[] = { + EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00), + EXYNOS_PIN_BANK_EINTN(2, 0x000, "etc1"), +}; + +/* + * Samsung pinctrl driver data for Exynos4415 SoC. Exynos4415 SoC includes + * three gpio/pin-mux/pinconfig controllers. + */ +const struct samsung_pin_ctrl exynos4415_pin_ctrl[] = { + { + /* pin-controller instance 0 data */ + .pin_banks = exynos4415_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos4415_pin_banks0), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 1 data */ + .pin_banks = exynos4415_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos4415_pin_banks1), + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 2 data */ + .pin_banks = exynos4415_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos4415_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, +}; + /* pin banks of exynos5250 pin-controller 0 */ static const struct samsung_pin_bank_data exynos5250_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index e5a8150..32940a0 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1231,6 +1231,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { .data = (void *)exynos4210_pin_ctrl }, { .compatible = "samsung,exynos4x12-pinctrl", .data = (void *)exynos4x12_pin_ctrl }, + { .compatible = "samsung,exynos4415-pinctrl", + .data = (void *)exynos4415_pin_ctrl }, { .compatible = "samsung,exynos5250-pinctrl", .data = (void *)exynos5250_pin_ctrl }, { .compatible = "samsung,exynos5260-pinctrl", diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index 29004be..1b8c013 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -267,6 +267,7 @@ struct samsung_pmx_func { extern const struct samsung_pin_ctrl exynos3250_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos4210_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; +extern const struct samsung_pin_ctrl exynos4415_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5420_pin_ctrl[]; -- cgit v1.1 From 2500bcc9da4f9e18854b1c360b3939bf06d3c7b9 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Mon, 3 Nov 2014 11:05:25 -0800 Subject: pinctrl: pinconf-generic: Declare dt_params/conf_items const Signed-off-by: Soren Brinkmann Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf-generic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index e28ef95..f78b416 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -38,7 +38,7 @@ struct pin_config_item { #define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \ .has_arg = d } -static struct pin_config_item conf_items[] = { +static const struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL, false), @@ -159,7 +159,7 @@ struct pinconf_generic_dt_params { u32 default_value; }; -static struct pinconf_generic_dt_params dt_params[] = { +static const struct pinconf_generic_dt_params dt_params[] = { { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 }, { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 }, @@ -209,7 +209,7 @@ int pinconf_generic_parse_dt_config(struct device_node *np, return -ENOMEM; for (i = 0; i < ARRAY_SIZE(dt_params); i++) { - struct pinconf_generic_dt_params *par = &dt_params[i]; + const struct pinconf_generic_dt_params *par = &dt_params[i]; ret = of_property_read_u32(np, par->property, &val); /* property not found */ -- cgit v1.1 From 842e528e1abf1edaa6467c6dbda299ec724cb42a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 14 Nov 2014 13:32:56 -0800 Subject: gpio: tz1090: Fix error handling of irq_of_parse_and_map irq_of_parse_and_map() returns 0 on error, so testing for negative result never works. Signed-off-by: Dmitry Torokhov Acked-by: James Hogan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tz1090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index 5246a60..6107d06 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -446,7 +446,7 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) bank->irq = irq_of_parse_and_map(np, 0); /* The interrupt is optional (it may be used by another core on chip) */ - if (bank->irq < 0) { + if (!bank->irq) { dev_info(dev, "IRQ not provided for bank %u, IRQs disabled\n", info->index); return 0; -- cgit v1.1 From 853b6bf044dcced57c523dbddabf8942e907be6e Mon Sep 17 00:00:00 2001 From: Matthieu Crapet Date: Tue, 18 Nov 2014 15:43:45 +0100 Subject: pinctrl: at91: enhance (debugfs) at91_gpio_dbg_show When a pin is configured as GPIO, print also direction (input or output). Signed-off-by: Matthieu Crapet Signed-off-by: Nicolas Ferre Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-at91.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 94643bb..66db984 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1342,7 +1342,6 @@ static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) for (i = 0; i < chip->ngpio; i++) { unsigned mask = pin_to_mask(i); const char *gpio_label; - u32 pdsr; gpio_label = gpiochip_is_requested(chip, i); if (!gpio_label) @@ -1351,11 +1350,13 @@ static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_printf(s, "[%s] GPIO%s%d: ", gpio_label, chip->label, i); if (mode == AT91_MUX_GPIO) { - pdsr = readl_relaxed(pio + PIO_PDSR); - - seq_printf(s, "[gpio] %s\n", - pdsr & mask ? - "set" : "clear"); + seq_printf(s, "[gpio] "); + seq_printf(s, "%s ", + readl_relaxed(pio + PIO_OSR) & mask ? + "output" : "input"); + seq_printf(s, "%s\n", + readl_relaxed(pio + PIO_PDSR) & mask ? + "set" : "clear"); } else { seq_printf(s, "[periph %c]\n", mode + 'A' - 1); -- cgit v1.1