18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (C) 2015-2017 Socionext Inc. 48c2ecf20Sopenharmony_ci// Author: Masahiro Yamada <yamada.masahiro@socionext.com> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/list.h> 78c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 88c2ecf20Sopenharmony_ci#include <linux/of.h> 98c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 108c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 118c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 128c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/regmap.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "../core.h" 178c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h" 188c2ecf20Sopenharmony_ci#include "pinctrl-uniphier.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define UNIPHIER_PINCTRL_PINMUX_BASE 0x1000 218c2ecf20Sopenharmony_ci#define UNIPHIER_PINCTRL_LOAD_PINMUX 0x1700 228c2ecf20Sopenharmony_ci#define UNIPHIER_PINCTRL_DRVCTRL_BASE 0x1800 238c2ecf20Sopenharmony_ci#define UNIPHIER_PINCTRL_DRV2CTRL_BASE 0x1900 248c2ecf20Sopenharmony_ci#define UNIPHIER_PINCTRL_DRV3CTRL_BASE 0x1980 258c2ecf20Sopenharmony_ci#define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0x1a00 268c2ecf20Sopenharmony_ci#define UNIPHIER_PINCTRL_IECTRL_BASE 0x1d00 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct uniphier_pinctrl_reg_region { 298c2ecf20Sopenharmony_ci struct list_head node; 308c2ecf20Sopenharmony_ci unsigned int base; 318c2ecf20Sopenharmony_ci unsigned int nregs; 328c2ecf20Sopenharmony_ci u32 vals[]; 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct uniphier_pinctrl_priv { 368c2ecf20Sopenharmony_ci struct pinctrl_desc pctldesc; 378c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev; 388c2ecf20Sopenharmony_ci struct regmap *regmap; 398c2ecf20Sopenharmony_ci const struct uniphier_pinctrl_socdata *socdata; 408c2ecf20Sopenharmony_ci struct list_head reg_regions; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int uniphier_pctl_get_groups_count(struct pinctrl_dev *pctldev) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return priv->socdata->groups_count; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const char *uniphier_pctl_get_group_name(struct pinctrl_dev *pctldev, 518c2ecf20Sopenharmony_ci unsigned selector) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return priv->socdata->groups[selector].name; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev, 598c2ecf20Sopenharmony_ci unsigned selector, 608c2ecf20Sopenharmony_ci const unsigned **pins, 618c2ecf20Sopenharmony_ci unsigned *num_pins) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci *pins = priv->socdata->groups[selector].pins; 668c2ecf20Sopenharmony_ci *num_pins = priv->socdata->groups[selector].num_pins; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 728c2ecf20Sopenharmony_cistatic void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, 738c2ecf20Sopenharmony_ci struct seq_file *s, unsigned offset) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci const struct pin_desc *desc = pin_desc_get(pctldev, offset); 768c2ecf20Sopenharmony_ci const char *pull_dir, *drv_type; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci switch (uniphier_pin_get_pull_dir(desc->drv_data)) { 798c2ecf20Sopenharmony_ci case UNIPHIER_PIN_PULL_UP: 808c2ecf20Sopenharmony_ci pull_dir = "UP"; 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci case UNIPHIER_PIN_PULL_DOWN: 838c2ecf20Sopenharmony_ci pull_dir = "DOWN"; 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci case UNIPHIER_PIN_PULL_UP_FIXED: 868c2ecf20Sopenharmony_ci pull_dir = "UP(FIXED)"; 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci case UNIPHIER_PIN_PULL_DOWN_FIXED: 898c2ecf20Sopenharmony_ci pull_dir = "DOWN(FIXED)"; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci case UNIPHIER_PIN_PULL_NONE: 928c2ecf20Sopenharmony_ci pull_dir = "NONE"; 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci default: 958c2ecf20Sopenharmony_ci BUG(); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci switch (uniphier_pin_get_drv_type(desc->drv_data)) { 998c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_1BIT: 1008c2ecf20Sopenharmony_ci drv_type = "4/8(mA)"; 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_2BIT: 1038c2ecf20Sopenharmony_ci drv_type = "8/12/16/20(mA)"; 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_3BIT: 1068c2ecf20Sopenharmony_ci drv_type = "4/5/7/9/11/12/14/16(mA)"; 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_FIXED4: 1098c2ecf20Sopenharmony_ci drv_type = "4(mA)"; 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_FIXED5: 1128c2ecf20Sopenharmony_ci drv_type = "5(mA)"; 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_FIXED8: 1158c2ecf20Sopenharmony_ci drv_type = "8(mA)"; 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_NONE: 1188c2ecf20Sopenharmony_ci drv_type = "NONE"; 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci default: 1218c2ecf20Sopenharmony_ci BUG(); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci seq_printf(s, " PULL_DIR=%s DRV_TYPE=%s", pull_dir, drv_type); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci#endif 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic const struct pinctrl_ops uniphier_pctlops = { 1298c2ecf20Sopenharmony_ci .get_groups_count = uniphier_pctl_get_groups_count, 1308c2ecf20Sopenharmony_ci .get_group_name = uniphier_pctl_get_group_name, 1318c2ecf20Sopenharmony_ci .get_group_pins = uniphier_pctl_get_group_pins, 1328c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 1338c2ecf20Sopenharmony_ci .pin_dbg_show = uniphier_pctl_pin_dbg_show, 1348c2ecf20Sopenharmony_ci#endif 1358c2ecf20Sopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_all, 1368c2ecf20Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic const unsigned int uniphier_conf_drv_strengths_1bit[] = {4, 8}; 1408c2ecf20Sopenharmony_cistatic const unsigned int uniphier_conf_drv_strengths_2bit[] = {8, 12, 16, 20}; 1418c2ecf20Sopenharmony_cistatic const unsigned int uniphier_conf_drv_strengths_3bit[] = {4, 5, 7, 9, 11, 1428c2ecf20Sopenharmony_ci 12, 14, 16}; 1438c2ecf20Sopenharmony_cistatic const unsigned int uniphier_conf_drv_strengths_fixed4[] = {4}; 1448c2ecf20Sopenharmony_cistatic const unsigned int uniphier_conf_drv_strengths_fixed5[] = {5}; 1458c2ecf20Sopenharmony_cistatic const unsigned int uniphier_conf_drv_strengths_fixed8[] = {8}; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int uniphier_conf_get_drvctrl_data(struct pinctrl_dev *pctldev, 1488c2ecf20Sopenharmony_ci unsigned int pin, unsigned int *reg, 1498c2ecf20Sopenharmony_ci unsigned int *shift, 1508c2ecf20Sopenharmony_ci unsigned int *mask, 1518c2ecf20Sopenharmony_ci const unsigned int **strengths) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci const struct pin_desc *desc = pin_desc_get(pctldev, pin); 1548c2ecf20Sopenharmony_ci enum uniphier_pin_drv_type type = 1558c2ecf20Sopenharmony_ci uniphier_pin_get_drv_type(desc->drv_data); 1568c2ecf20Sopenharmony_ci unsigned int base = 0; 1578c2ecf20Sopenharmony_ci unsigned int stride = 0; 1588c2ecf20Sopenharmony_ci unsigned int width = 0; 1598c2ecf20Sopenharmony_ci unsigned int drvctrl; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci switch (type) { 1628c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_1BIT: 1638c2ecf20Sopenharmony_ci *strengths = uniphier_conf_drv_strengths_1bit; 1648c2ecf20Sopenharmony_ci base = UNIPHIER_PINCTRL_DRVCTRL_BASE; 1658c2ecf20Sopenharmony_ci stride = 1; 1668c2ecf20Sopenharmony_ci width = 1; 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_2BIT: 1698c2ecf20Sopenharmony_ci *strengths = uniphier_conf_drv_strengths_2bit; 1708c2ecf20Sopenharmony_ci base = UNIPHIER_PINCTRL_DRV2CTRL_BASE; 1718c2ecf20Sopenharmony_ci stride = 2; 1728c2ecf20Sopenharmony_ci width = 2; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_3BIT: 1758c2ecf20Sopenharmony_ci *strengths = uniphier_conf_drv_strengths_3bit; 1768c2ecf20Sopenharmony_ci base = UNIPHIER_PINCTRL_DRV3CTRL_BASE; 1778c2ecf20Sopenharmony_ci stride = 4; 1788c2ecf20Sopenharmony_ci width = 3; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_FIXED4: 1818c2ecf20Sopenharmony_ci *strengths = uniphier_conf_drv_strengths_fixed4; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_FIXED5: 1848c2ecf20Sopenharmony_ci *strengths = uniphier_conf_drv_strengths_fixed5; 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_FIXED8: 1878c2ecf20Sopenharmony_ci *strengths = uniphier_conf_drv_strengths_fixed8; 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci default: 1908c2ecf20Sopenharmony_ci /* drive strength control is not supported for this pin */ 1918c2ecf20Sopenharmony_ci return -EINVAL; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci drvctrl = uniphier_pin_get_drvctrl(desc->drv_data); 1958c2ecf20Sopenharmony_ci drvctrl *= stride; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci *reg = base + drvctrl / 32 * 4; 1988c2ecf20Sopenharmony_ci *shift = drvctrl % 32; 1998c2ecf20Sopenharmony_ci *mask = (1U << width) - 1; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, 2058c2ecf20Sopenharmony_ci unsigned int pin, 2068c2ecf20Sopenharmony_ci enum pin_config_param param) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 2098c2ecf20Sopenharmony_ci const struct pin_desc *desc = pin_desc_get(pctldev, pin); 2108c2ecf20Sopenharmony_ci enum uniphier_pin_pull_dir pull_dir = 2118c2ecf20Sopenharmony_ci uniphier_pin_get_pull_dir(desc->drv_data); 2128c2ecf20Sopenharmony_ci unsigned int pupdctrl, reg, shift, val; 2138c2ecf20Sopenharmony_ci unsigned int expected = 1; 2148c2ecf20Sopenharmony_ci int ret; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci switch (param) { 2178c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 2188c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_NONE) 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || 2218c2ecf20Sopenharmony_ci pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) 2228c2ecf20Sopenharmony_ci return -EINVAL; 2238c2ecf20Sopenharmony_ci expected = 0; 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 2268c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED) 2278c2ecf20Sopenharmony_ci return 0; 2288c2ecf20Sopenharmony_ci if (pull_dir != UNIPHIER_PIN_PULL_UP) 2298c2ecf20Sopenharmony_ci return -EINVAL; 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 2328c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci if (pull_dir != UNIPHIER_PIN_PULL_DOWN) 2358c2ecf20Sopenharmony_ci return -EINVAL; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci default: 2388c2ecf20Sopenharmony_ci BUG(); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; 2448c2ecf20Sopenharmony_ci shift = pupdctrl % 32; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci ret = regmap_read(priv->regmap, reg, &val); 2478c2ecf20Sopenharmony_ci if (ret) 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci val = (val >> shift) & 1; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return (val == expected) ? 0 : -EINVAL; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, 2568c2ecf20Sopenharmony_ci unsigned int pin, u32 *strength) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 2598c2ecf20Sopenharmony_ci unsigned int reg, shift, mask, val; 2608c2ecf20Sopenharmony_ci const unsigned int *strengths; 2618c2ecf20Sopenharmony_ci int ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci ret = uniphier_conf_get_drvctrl_data(pctldev, pin, ®, &shift, 2648c2ecf20Sopenharmony_ci &mask, &strengths); 2658c2ecf20Sopenharmony_ci if (ret) 2668c2ecf20Sopenharmony_ci return ret; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (mask) { 2698c2ecf20Sopenharmony_ci ret = regmap_read(priv->regmap, reg, &val); 2708c2ecf20Sopenharmony_ci if (ret) 2718c2ecf20Sopenharmony_ci return ret; 2728c2ecf20Sopenharmony_ci } else { 2738c2ecf20Sopenharmony_ci val = 0; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci *strength = strengths[(val >> shift) & mask]; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return 0; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev, 2828c2ecf20Sopenharmony_ci unsigned int pin) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 2858c2ecf20Sopenharmony_ci const struct pin_desc *desc = pin_desc_get(pctldev, pin); 2868c2ecf20Sopenharmony_ci unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data); 2878c2ecf20Sopenharmony_ci unsigned int reg, mask, val; 2888c2ecf20Sopenharmony_ci int ret; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (iectrl == UNIPHIER_PIN_IECTRL_NONE) 2918c2ecf20Sopenharmony_ci /* This pin is always input-enabled. */ 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) 2958c2ecf20Sopenharmony_ci iectrl = pin; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci reg = UNIPHIER_PINCTRL_IECTRL_BASE + iectrl / 32 * 4; 2988c2ecf20Sopenharmony_ci mask = BIT(iectrl % 32); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ret = regmap_read(priv->regmap, reg, &val); 3018c2ecf20Sopenharmony_ci if (ret) 3028c2ecf20Sopenharmony_ci return ret; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return val & mask ? 0 : -EINVAL; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev, 3088c2ecf20Sopenharmony_ci unsigned pin, 3098c2ecf20Sopenharmony_ci unsigned long *configs) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci enum pin_config_param param = pinconf_to_config_param(*configs); 3128c2ecf20Sopenharmony_ci bool has_arg = false; 3138c2ecf20Sopenharmony_ci u32 arg; 3148c2ecf20Sopenharmony_ci int ret; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci switch (param) { 3178c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 3188c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 3198c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 3208c2ecf20Sopenharmony_ci ret = uniphier_conf_pin_bias_get(pctldev, pin, param); 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 3238c2ecf20Sopenharmony_ci ret = uniphier_conf_pin_drive_get(pctldev, pin, &arg); 3248c2ecf20Sopenharmony_ci has_arg = true; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 3278c2ecf20Sopenharmony_ci ret = uniphier_conf_pin_input_enable_get(pctldev, pin); 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci default: 3308c2ecf20Sopenharmony_ci /* unsupported parameter */ 3318c2ecf20Sopenharmony_ci ret = -EINVAL; 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (ret == 0 && has_arg) 3368c2ecf20Sopenharmony_ci *configs = pinconf_to_config_packed(param, arg); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, 3428c2ecf20Sopenharmony_ci unsigned int pin, 3438c2ecf20Sopenharmony_ci enum pin_config_param param, u32 arg) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 3468c2ecf20Sopenharmony_ci const struct pin_desc *desc = pin_desc_get(pctldev, pin); 3478c2ecf20Sopenharmony_ci enum uniphier_pin_pull_dir pull_dir = 3488c2ecf20Sopenharmony_ci uniphier_pin_get_pull_dir(desc->drv_data); 3498c2ecf20Sopenharmony_ci unsigned int pupdctrl, reg, shift; 3508c2ecf20Sopenharmony_ci unsigned int val = 1; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci switch (param) { 3538c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 3548c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_NONE) 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || 3578c2ecf20Sopenharmony_ci pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) { 3588c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 3598c2ecf20Sopenharmony_ci "can not disable pull register for pin %s\n", 3608c2ecf20Sopenharmony_ci desc->name); 3618c2ecf20Sopenharmony_ci return -EINVAL; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci val = 0; 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 3668c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED && arg != 0) 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci if (pull_dir != UNIPHIER_PIN_PULL_UP) { 3698c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 3708c2ecf20Sopenharmony_ci "pull-up is unsupported for pin %s\n", 3718c2ecf20Sopenharmony_ci desc->name); 3728c2ecf20Sopenharmony_ci return -EINVAL; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci if (arg == 0) { 3758c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "pull-up can not be total\n"); 3768c2ecf20Sopenharmony_ci return -EINVAL; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 3808c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED && arg != 0) 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci if (pull_dir != UNIPHIER_PIN_PULL_DOWN) { 3838c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 3848c2ecf20Sopenharmony_ci "pull-down is unsupported for pin %s\n", 3858c2ecf20Sopenharmony_ci desc->name); 3868c2ecf20Sopenharmony_ci return -EINVAL; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci if (arg == 0) { 3898c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "pull-down can not be total\n"); 3908c2ecf20Sopenharmony_ci return -EINVAL; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: 3948c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_NONE) { 3958c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 3968c2ecf20Sopenharmony_ci "pull-up/down is unsupported for pin %s\n", 3978c2ecf20Sopenharmony_ci desc->name); 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (arg == 0) 4028c2ecf20Sopenharmony_ci return 0; /* configuration ingored */ 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci default: 4058c2ecf20Sopenharmony_ci BUG(); 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; 4118c2ecf20Sopenharmony_ci shift = pupdctrl % 32; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return regmap_update_bits(priv->regmap, reg, 1 << shift, val << shift); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, 4178c2ecf20Sopenharmony_ci unsigned int pin, u32 strength) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 4208c2ecf20Sopenharmony_ci const struct pin_desc *desc = pin_desc_get(pctldev, pin); 4218c2ecf20Sopenharmony_ci unsigned int reg, shift, mask, val; 4228c2ecf20Sopenharmony_ci const unsigned int *strengths; 4238c2ecf20Sopenharmony_ci int ret; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = uniphier_conf_get_drvctrl_data(pctldev, pin, ®, &shift, 4268c2ecf20Sopenharmony_ci &mask, &strengths); 4278c2ecf20Sopenharmony_ci if (ret) { 4288c2ecf20Sopenharmony_ci dev_err(pctldev->dev, "cannot set drive strength for pin %s\n", 4298c2ecf20Sopenharmony_ci desc->name); 4308c2ecf20Sopenharmony_ci return ret; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci for (val = 0; val <= mask; val++) { 4348c2ecf20Sopenharmony_ci if (strengths[val] > strength) 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (val == 0) { 4398c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 4408c2ecf20Sopenharmony_ci "unsupported drive strength %u mA for pin %s\n", 4418c2ecf20Sopenharmony_ci strength, desc->name); 4428c2ecf20Sopenharmony_ci return -EINVAL; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (!mask) 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci val--; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return regmap_update_bits(priv->regmap, reg, 4518c2ecf20Sopenharmony_ci mask << shift, val << shift); 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev, 4558c2ecf20Sopenharmony_ci unsigned int pin, u32 enable) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 4588c2ecf20Sopenharmony_ci const struct pin_desc *desc = pin_desc_get(pctldev, pin); 4598c2ecf20Sopenharmony_ci unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data); 4608c2ecf20Sopenharmony_ci unsigned int reg, mask; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* 4638c2ecf20Sopenharmony_ci * Multiple pins share one input enable, per-pin disabling is 4648c2ecf20Sopenharmony_ci * impossible. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci if (!(priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) && 4678c2ecf20Sopenharmony_ci !enable) 4688c2ecf20Sopenharmony_ci return -EINVAL; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* UNIPHIER_PIN_IECTRL_NONE means the pin is always input-enabled */ 4718c2ecf20Sopenharmony_ci if (iectrl == UNIPHIER_PIN_IECTRL_NONE) 4728c2ecf20Sopenharmony_ci return enable ? 0 : -EINVAL; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) 4758c2ecf20Sopenharmony_ci iectrl = pin; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci reg = UNIPHIER_PINCTRL_IECTRL_BASE + iectrl / 32 * 4; 4788c2ecf20Sopenharmony_ci mask = BIT(iectrl % 32); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci return regmap_update_bits(priv->regmap, reg, mask, enable ? mask : 0); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev, 4848c2ecf20Sopenharmony_ci unsigned pin, 4858c2ecf20Sopenharmony_ci unsigned long *configs, 4868c2ecf20Sopenharmony_ci unsigned num_configs) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci int i, ret; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 4918c2ecf20Sopenharmony_ci enum pin_config_param param = 4928c2ecf20Sopenharmony_ci pinconf_to_config_param(configs[i]); 4938c2ecf20Sopenharmony_ci u32 arg = pinconf_to_config_argument(configs[i]); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci switch (param) { 4968c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 4978c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 4988c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 4998c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: 5008c2ecf20Sopenharmony_ci ret = uniphier_conf_pin_bias_set(pctldev, pin, 5018c2ecf20Sopenharmony_ci param, arg); 5028c2ecf20Sopenharmony_ci break; 5038c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 5048c2ecf20Sopenharmony_ci ret = uniphier_conf_pin_drive_set(pctldev, pin, arg); 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 5078c2ecf20Sopenharmony_ci ret = uniphier_conf_pin_input_enable(pctldev, pin, arg); 5088c2ecf20Sopenharmony_ci break; 5098c2ecf20Sopenharmony_ci default: 5108c2ecf20Sopenharmony_ci dev_err(pctldev->dev, 5118c2ecf20Sopenharmony_ci "unsupported configuration parameter %u\n", 5128c2ecf20Sopenharmony_ci param); 5138c2ecf20Sopenharmony_ci return -EINVAL; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (ret) 5178c2ecf20Sopenharmony_ci return ret; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic int uniphier_conf_pin_config_group_set(struct pinctrl_dev *pctldev, 5248c2ecf20Sopenharmony_ci unsigned selector, 5258c2ecf20Sopenharmony_ci unsigned long *configs, 5268c2ecf20Sopenharmony_ci unsigned num_configs) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 5298c2ecf20Sopenharmony_ci const unsigned *pins = priv->socdata->groups[selector].pins; 5308c2ecf20Sopenharmony_ci unsigned num_pins = priv->socdata->groups[selector].num_pins; 5318c2ecf20Sopenharmony_ci int i, ret; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci for (i = 0; i < num_pins; i++) { 5348c2ecf20Sopenharmony_ci ret = uniphier_conf_pin_config_set(pctldev, pins[i], 5358c2ecf20Sopenharmony_ci configs, num_configs); 5368c2ecf20Sopenharmony_ci if (ret) 5378c2ecf20Sopenharmony_ci return ret; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic const struct pinconf_ops uniphier_confops = { 5448c2ecf20Sopenharmony_ci .is_generic = true, 5458c2ecf20Sopenharmony_ci .pin_config_get = uniphier_conf_pin_config_get, 5468c2ecf20Sopenharmony_ci .pin_config_set = uniphier_conf_pin_config_set, 5478c2ecf20Sopenharmony_ci .pin_config_group_set = uniphier_conf_pin_config_group_set, 5488c2ecf20Sopenharmony_ci}; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic int uniphier_pmx_get_functions_count(struct pinctrl_dev *pctldev) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return priv->socdata->functions_count; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic const char *uniphier_pmx_get_function_name(struct pinctrl_dev *pctldev, 5588c2ecf20Sopenharmony_ci unsigned selector) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci return priv->socdata->functions[selector].name; 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev, 5668c2ecf20Sopenharmony_ci unsigned selector, 5678c2ecf20Sopenharmony_ci const char * const **groups, 5688c2ecf20Sopenharmony_ci unsigned *num_groups) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci *groups = priv->socdata->functions[selector].groups; 5738c2ecf20Sopenharmony_ci *num_groups = priv->socdata->functions[selector].num_groups; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return 0; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin, 5798c2ecf20Sopenharmony_ci int muxval) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 5828c2ecf20Sopenharmony_ci unsigned int mux_bits, reg_stride, reg, reg_end, shift, mask; 5838c2ecf20Sopenharmony_ci bool load_pinctrl; 5848c2ecf20Sopenharmony_ci int ret; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* some pins need input-enabling */ 5878c2ecf20Sopenharmony_ci ret = uniphier_conf_pin_input_enable(pctldev, pin, 1); 5888c2ecf20Sopenharmony_ci if (ret) 5898c2ecf20Sopenharmony_ci return ret; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (muxval < 0) 5928c2ecf20Sopenharmony_ci return 0; /* dedicated pin; nothing to do for pin-mux */ 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) { 5958c2ecf20Sopenharmony_ci /* 5968c2ecf20Sopenharmony_ci * Mode reg_offset bit_position 5978c2ecf20Sopenharmony_ci * Normal 4 * n shift+3:shift 5988c2ecf20Sopenharmony_ci * Debug 4 * n shift+7:shift+4 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci mux_bits = 4; 6018c2ecf20Sopenharmony_ci reg_stride = 8; 6028c2ecf20Sopenharmony_ci load_pinctrl = true; 6038c2ecf20Sopenharmony_ci } else { 6048c2ecf20Sopenharmony_ci /* 6058c2ecf20Sopenharmony_ci * Mode reg_offset bit_position 6068c2ecf20Sopenharmony_ci * Normal 8 * n shift+3:shift 6078c2ecf20Sopenharmony_ci * Debug 8 * n + 4 shift+3:shift 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci mux_bits = 8; 6108c2ecf20Sopenharmony_ci reg_stride = 4; 6118c2ecf20Sopenharmony_ci load_pinctrl = false; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; 6158c2ecf20Sopenharmony_ci reg_end = reg + reg_stride; 6168c2ecf20Sopenharmony_ci shift = pin * mux_bits % 32; 6178c2ecf20Sopenharmony_ci mask = (1U << mux_bits) - 1; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* 6208c2ecf20Sopenharmony_ci * If reg_stride is greater than 4, the MSB of each pinsel shall be 6218c2ecf20Sopenharmony_ci * stored in the offset+4. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci for (; reg < reg_end; reg += 4) { 6248c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap, reg, 6258c2ecf20Sopenharmony_ci mask << shift, muxval << shift); 6268c2ecf20Sopenharmony_ci if (ret) 6278c2ecf20Sopenharmony_ci return ret; 6288c2ecf20Sopenharmony_ci muxval >>= mux_bits; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (load_pinctrl) { 6328c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, 6338c2ecf20Sopenharmony_ci UNIPHIER_PINCTRL_LOAD_PINMUX, 1); 6348c2ecf20Sopenharmony_ci if (ret) 6358c2ecf20Sopenharmony_ci return ret; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci return 0; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int uniphier_pmx_set_mux(struct pinctrl_dev *pctldev, 6428c2ecf20Sopenharmony_ci unsigned func_selector, 6438c2ecf20Sopenharmony_ci unsigned group_selector) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 6468c2ecf20Sopenharmony_ci const struct uniphier_pinctrl_group *grp = 6478c2ecf20Sopenharmony_ci &priv->socdata->groups[group_selector]; 6488c2ecf20Sopenharmony_ci int i; 6498c2ecf20Sopenharmony_ci int ret; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci for (i = 0; i < grp->num_pins; i++) { 6528c2ecf20Sopenharmony_ci ret = uniphier_pmx_set_one_mux(pctldev, grp->pins[i], 6538c2ecf20Sopenharmony_ci grp->muxvals[i]); 6548c2ecf20Sopenharmony_ci if (ret) 6558c2ecf20Sopenharmony_ci return ret; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return 0; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic int uniphier_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, 6628c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 6638c2ecf20Sopenharmony_ci unsigned offset) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 6668c2ecf20Sopenharmony_ci unsigned int gpio_offset; 6678c2ecf20Sopenharmony_ci int muxval, i; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (range->pins) { 6708c2ecf20Sopenharmony_ci for (i = 0; i < range->npins; i++) 6718c2ecf20Sopenharmony_ci if (range->pins[i] == offset) 6728c2ecf20Sopenharmony_ci break; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (WARN_ON(i == range->npins)) 6758c2ecf20Sopenharmony_ci return -EINVAL; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci gpio_offset = i; 6788c2ecf20Sopenharmony_ci } else { 6798c2ecf20Sopenharmony_ci gpio_offset = offset - range->pin_base; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci gpio_offset += range->id; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci muxval = priv->socdata->get_gpio_muxval(offset, gpio_offset); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci return uniphier_pmx_set_one_mux(pctldev, offset, muxval); 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic const struct pinmux_ops uniphier_pmxops = { 6908c2ecf20Sopenharmony_ci .get_functions_count = uniphier_pmx_get_functions_count, 6918c2ecf20Sopenharmony_ci .get_function_name = uniphier_pmx_get_function_name, 6928c2ecf20Sopenharmony_ci .get_function_groups = uniphier_pmx_get_function_groups, 6938c2ecf20Sopenharmony_ci .set_mux = uniphier_pmx_set_mux, 6948c2ecf20Sopenharmony_ci .gpio_request_enable = uniphier_pmx_gpio_request_enable, 6958c2ecf20Sopenharmony_ci .strict = true, 6968c2ecf20Sopenharmony_ci}; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 6998c2ecf20Sopenharmony_cistatic int uniphier_pinctrl_suspend(struct device *dev) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = dev_get_drvdata(dev); 7028c2ecf20Sopenharmony_ci struct uniphier_pinctrl_reg_region *r; 7038c2ecf20Sopenharmony_ci int ret; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci list_for_each_entry(r, &priv->reg_regions, node) { 7068c2ecf20Sopenharmony_ci ret = regmap_bulk_read(priv->regmap, r->base, r->vals, 7078c2ecf20Sopenharmony_ci r->nregs); 7088c2ecf20Sopenharmony_ci if (ret) 7098c2ecf20Sopenharmony_ci return ret; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci return 0; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic int uniphier_pinctrl_resume(struct device *dev) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv = dev_get_drvdata(dev); 7188c2ecf20Sopenharmony_ci struct uniphier_pinctrl_reg_region *r; 7198c2ecf20Sopenharmony_ci int ret; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci list_for_each_entry(r, &priv->reg_regions, node) { 7228c2ecf20Sopenharmony_ci ret = regmap_bulk_write(priv->regmap, r->base, r->vals, 7238c2ecf20Sopenharmony_ci r->nregs); 7248c2ecf20Sopenharmony_ci if (ret) 7258c2ecf20Sopenharmony_ci return ret; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) { 7298c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, 7308c2ecf20Sopenharmony_ci UNIPHIER_PINCTRL_LOAD_PINMUX, 1); 7318c2ecf20Sopenharmony_ci if (ret) 7328c2ecf20Sopenharmony_ci return ret; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci return 0; 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic int uniphier_pinctrl_add_reg_region(struct device *dev, 7398c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv, 7408c2ecf20Sopenharmony_ci unsigned int base, 7418c2ecf20Sopenharmony_ci unsigned int count, 7428c2ecf20Sopenharmony_ci unsigned int width) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct uniphier_pinctrl_reg_region *region; 7458c2ecf20Sopenharmony_ci unsigned int nregs; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (!count) 7488c2ecf20Sopenharmony_ci return 0; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci nregs = DIV_ROUND_UP(count * width, 32); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci region = devm_kzalloc(dev, struct_size(region, vals, nregs), 7538c2ecf20Sopenharmony_ci GFP_KERNEL); 7548c2ecf20Sopenharmony_ci if (!region) 7558c2ecf20Sopenharmony_ci return -ENOMEM; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci region->base = base; 7588c2ecf20Sopenharmony_ci region->nregs = nregs; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci list_add_tail(®ion->node, &priv->reg_regions); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci return 0; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci#endif 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int uniphier_pinctrl_pm_init(struct device *dev, 7678c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 7708c2ecf20Sopenharmony_ci const struct uniphier_pinctrl_socdata *socdata = priv->socdata; 7718c2ecf20Sopenharmony_ci unsigned int num_drvctrl = 0; 7728c2ecf20Sopenharmony_ci unsigned int num_drv2ctrl = 0; 7738c2ecf20Sopenharmony_ci unsigned int num_drv3ctrl = 0; 7748c2ecf20Sopenharmony_ci unsigned int num_pupdctrl = 0; 7758c2ecf20Sopenharmony_ci unsigned int num_iectrl = 0; 7768c2ecf20Sopenharmony_ci unsigned int iectrl, drvctrl, pupdctrl; 7778c2ecf20Sopenharmony_ci enum uniphier_pin_drv_type drv_type; 7788c2ecf20Sopenharmony_ci enum uniphier_pin_pull_dir pull_dir; 7798c2ecf20Sopenharmony_ci int i, ret; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci for (i = 0; i < socdata->npins; i++) { 7828c2ecf20Sopenharmony_ci void *drv_data = socdata->pins[i].drv_data; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci drvctrl = uniphier_pin_get_drvctrl(drv_data); 7858c2ecf20Sopenharmony_ci drv_type = uniphier_pin_get_drv_type(drv_data); 7868c2ecf20Sopenharmony_ci pupdctrl = uniphier_pin_get_pupdctrl(drv_data); 7878c2ecf20Sopenharmony_ci pull_dir = uniphier_pin_get_pull_dir(drv_data); 7888c2ecf20Sopenharmony_ci iectrl = uniphier_pin_get_iectrl(drv_data); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci switch (drv_type) { 7918c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_1BIT: 7928c2ecf20Sopenharmony_ci num_drvctrl = max(num_drvctrl, drvctrl + 1); 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_2BIT: 7958c2ecf20Sopenharmony_ci num_drv2ctrl = max(num_drv2ctrl, drvctrl + 1); 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci case UNIPHIER_PIN_DRV_3BIT: 7988c2ecf20Sopenharmony_ci num_drv3ctrl = max(num_drv3ctrl, drvctrl + 1); 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci default: 8018c2ecf20Sopenharmony_ci break; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (pull_dir == UNIPHIER_PIN_PULL_UP || 8058c2ecf20Sopenharmony_ci pull_dir == UNIPHIER_PIN_PULL_DOWN) 8068c2ecf20Sopenharmony_ci num_pupdctrl = max(num_pupdctrl, pupdctrl + 1); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (iectrl != UNIPHIER_PIN_IECTRL_NONE) { 8098c2ecf20Sopenharmony_ci if (socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) 8108c2ecf20Sopenharmony_ci iectrl = i; 8118c2ecf20Sopenharmony_ci num_iectrl = max(num_iectrl, iectrl + 1); 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->reg_regions); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci ret = uniphier_pinctrl_add_reg_region(dev, priv, 8188c2ecf20Sopenharmony_ci UNIPHIER_PINCTRL_PINMUX_BASE, 8198c2ecf20Sopenharmony_ci socdata->npins, 8); 8208c2ecf20Sopenharmony_ci if (ret) 8218c2ecf20Sopenharmony_ci return ret; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci ret = uniphier_pinctrl_add_reg_region(dev, priv, 8248c2ecf20Sopenharmony_ci UNIPHIER_PINCTRL_DRVCTRL_BASE, 8258c2ecf20Sopenharmony_ci num_drvctrl, 1); 8268c2ecf20Sopenharmony_ci if (ret) 8278c2ecf20Sopenharmony_ci return ret; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci ret = uniphier_pinctrl_add_reg_region(dev, priv, 8308c2ecf20Sopenharmony_ci UNIPHIER_PINCTRL_DRV2CTRL_BASE, 8318c2ecf20Sopenharmony_ci num_drv2ctrl, 2); 8328c2ecf20Sopenharmony_ci if (ret) 8338c2ecf20Sopenharmony_ci return ret; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci ret = uniphier_pinctrl_add_reg_region(dev, priv, 8368c2ecf20Sopenharmony_ci UNIPHIER_PINCTRL_DRV3CTRL_BASE, 8378c2ecf20Sopenharmony_ci num_drv3ctrl, 3); 8388c2ecf20Sopenharmony_ci if (ret) 8398c2ecf20Sopenharmony_ci return ret; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci ret = uniphier_pinctrl_add_reg_region(dev, priv, 8428c2ecf20Sopenharmony_ci UNIPHIER_PINCTRL_PUPDCTRL_BASE, 8438c2ecf20Sopenharmony_ci num_pupdctrl, 1); 8448c2ecf20Sopenharmony_ci if (ret) 8458c2ecf20Sopenharmony_ci return ret; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci ret = uniphier_pinctrl_add_reg_region(dev, priv, 8488c2ecf20Sopenharmony_ci UNIPHIER_PINCTRL_IECTRL_BASE, 8498c2ecf20Sopenharmony_ci num_iectrl, 1); 8508c2ecf20Sopenharmony_ci if (ret) 8518c2ecf20Sopenharmony_ci return ret; 8528c2ecf20Sopenharmony_ci#endif 8538c2ecf20Sopenharmony_ci return 0; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ciconst struct dev_pm_ops uniphier_pinctrl_pm_ops = { 8578c2ecf20Sopenharmony_ci SET_LATE_SYSTEM_SLEEP_PM_OPS(uniphier_pinctrl_suspend, 8588c2ecf20Sopenharmony_ci uniphier_pinctrl_resume) 8598c2ecf20Sopenharmony_ci}; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ciint uniphier_pinctrl_probe(struct platform_device *pdev, 8628c2ecf20Sopenharmony_ci const struct uniphier_pinctrl_socdata *socdata) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 8658c2ecf20Sopenharmony_ci struct uniphier_pinctrl_priv *priv; 8668c2ecf20Sopenharmony_ci struct device_node *parent; 8678c2ecf20Sopenharmony_ci int ret; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (!socdata || 8708c2ecf20Sopenharmony_ci !socdata->pins || !socdata->npins || 8718c2ecf20Sopenharmony_ci !socdata->groups || !socdata->groups_count || 8728c2ecf20Sopenharmony_ci !socdata->functions || !socdata->functions_count) { 8738c2ecf20Sopenharmony_ci dev_err(dev, "pinctrl socdata lacks necessary members\n"); 8748c2ecf20Sopenharmony_ci return -EINVAL; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 8788c2ecf20Sopenharmony_ci if (!priv) 8798c2ecf20Sopenharmony_ci return -ENOMEM; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci parent = of_get_parent(dev->of_node); 8828c2ecf20Sopenharmony_ci priv->regmap = syscon_node_to_regmap(parent); 8838c2ecf20Sopenharmony_ci of_node_put(parent); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (IS_ERR(priv->regmap)) { 8868c2ecf20Sopenharmony_ci dev_err(dev, "failed to get regmap\n"); 8878c2ecf20Sopenharmony_ci return PTR_ERR(priv->regmap); 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci priv->socdata = socdata; 8918c2ecf20Sopenharmony_ci priv->pctldesc.name = dev->driver->name; 8928c2ecf20Sopenharmony_ci priv->pctldesc.pins = socdata->pins; 8938c2ecf20Sopenharmony_ci priv->pctldesc.npins = socdata->npins; 8948c2ecf20Sopenharmony_ci priv->pctldesc.pctlops = &uniphier_pctlops; 8958c2ecf20Sopenharmony_ci priv->pctldesc.pmxops = &uniphier_pmxops; 8968c2ecf20Sopenharmony_ci priv->pctldesc.confops = &uniphier_confops; 8978c2ecf20Sopenharmony_ci priv->pctldesc.owner = dev->driver->owner; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci ret = uniphier_pinctrl_pm_init(dev, priv); 9008c2ecf20Sopenharmony_ci if (ret) 9018c2ecf20Sopenharmony_ci return ret; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci priv->pctldev = devm_pinctrl_register(dev, &priv->pctldesc, priv); 9048c2ecf20Sopenharmony_ci if (IS_ERR(priv->pctldev)) { 9058c2ecf20Sopenharmony_ci dev_err(dev, "failed to register UniPhier pinctrl driver\n"); 9068c2ecf20Sopenharmony_ci return PTR_ERR(priv->pctldev); 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci return 0; 9128c2ecf20Sopenharmony_ci} 913