18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Spreadtrum pin controller driver 48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Spreadtrum - http://www.spreadtrum.com 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 88c2ecf20Sopenharmony_ci#include <linux/err.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci#include <linux/of_device.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h> 178c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 188c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 198c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 208c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "../core.h" 248c2ecf20Sopenharmony_ci#include "../pinmux.h" 258c2ecf20Sopenharmony_ci#include "../pinconf.h" 268c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h" 278c2ecf20Sopenharmony_ci#include "pinctrl-sprd.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define PINCTRL_BIT_MASK(width) (~(~0UL << (width))) 308c2ecf20Sopenharmony_ci#define PINCTRL_REG_OFFSET 0x20 318c2ecf20Sopenharmony_ci#define PINCTRL_REG_MISC_OFFSET 0x4020 328c2ecf20Sopenharmony_ci#define PINCTRL_REG_LEN 0x4 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define PIN_FUNC_MASK (BIT(4) | BIT(5)) 358c2ecf20Sopenharmony_ci#define PIN_FUNC_SEL_1 ~PIN_FUNC_MASK 368c2ecf20Sopenharmony_ci#define PIN_FUNC_SEL_2 BIT(4) 378c2ecf20Sopenharmony_ci#define PIN_FUNC_SEL_3 BIT(5) 388c2ecf20Sopenharmony_ci#define PIN_FUNC_SEL_4 PIN_FUNC_MASK 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define AP_SLEEP_MODE BIT(13) 418c2ecf20Sopenharmony_ci#define PUBCP_SLEEP_MODE BIT(14) 428c2ecf20Sopenharmony_ci#define TGLDSP_SLEEP_MODE BIT(15) 438c2ecf20Sopenharmony_ci#define AGDSP_SLEEP_MODE BIT(16) 448c2ecf20Sopenharmony_ci#define CM4_SLEEP_MODE BIT(17) 458c2ecf20Sopenharmony_ci#define SLEEP_MODE_MASK GENMASK(5, 0) 468c2ecf20Sopenharmony_ci#define SLEEP_MODE_SHIFT 13 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define SLEEP_INPUT BIT(1) 498c2ecf20Sopenharmony_ci#define SLEEP_INPUT_MASK 0x1 508c2ecf20Sopenharmony_ci#define SLEEP_INPUT_SHIFT 1 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define SLEEP_OUTPUT BIT(0) 538c2ecf20Sopenharmony_ci#define SLEEP_OUTPUT_MASK 0x1 548c2ecf20Sopenharmony_ci#define SLEEP_OUTPUT_SHIFT 0 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define DRIVE_STRENGTH_MASK GENMASK(3, 0) 578c2ecf20Sopenharmony_ci#define DRIVE_STRENGTH_SHIFT 19 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define SLEEP_PULL_DOWN BIT(2) 608c2ecf20Sopenharmony_ci#define SLEEP_PULL_DOWN_MASK 0x1 618c2ecf20Sopenharmony_ci#define SLEEP_PULL_DOWN_SHIFT 2 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define PULL_DOWN BIT(6) 648c2ecf20Sopenharmony_ci#define PULL_DOWN_MASK 0x1 658c2ecf20Sopenharmony_ci#define PULL_DOWN_SHIFT 6 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define SLEEP_PULL_UP BIT(3) 688c2ecf20Sopenharmony_ci#define SLEEP_PULL_UP_MASK 0x1 698c2ecf20Sopenharmony_ci#define SLEEP_PULL_UP_SHIFT 3 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define PULL_UP_4_7K (BIT(12) | BIT(7)) 728c2ecf20Sopenharmony_ci#define PULL_UP_20K BIT(7) 738c2ecf20Sopenharmony_ci#define PULL_UP_MASK 0x21 748c2ecf20Sopenharmony_ci#define PULL_UP_SHIFT 7 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define INPUT_SCHMITT BIT(11) 778c2ecf20Sopenharmony_ci#define INPUT_SCHMITT_MASK 0x1 788c2ecf20Sopenharmony_ci#define INPUT_SCHMITT_SHIFT 11 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cienum pin_sleep_mode { 818c2ecf20Sopenharmony_ci AP_SLEEP = BIT(0), 828c2ecf20Sopenharmony_ci PUBCP_SLEEP = BIT(1), 838c2ecf20Sopenharmony_ci TGLDSP_SLEEP = BIT(2), 848c2ecf20Sopenharmony_ci AGDSP_SLEEP = BIT(3), 858c2ecf20Sopenharmony_ci CM4_SLEEP = BIT(4), 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cienum pin_func_sel { 898c2ecf20Sopenharmony_ci PIN_FUNC_1, 908c2ecf20Sopenharmony_ci PIN_FUNC_2, 918c2ecf20Sopenharmony_ci PIN_FUNC_3, 928c2ecf20Sopenharmony_ci PIN_FUNC_4, 938c2ecf20Sopenharmony_ci PIN_FUNC_MAX, 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/** 978c2ecf20Sopenharmony_ci * struct sprd_pin: represent one pin's description 988c2ecf20Sopenharmony_ci * @name: pin name 998c2ecf20Sopenharmony_ci * @number: pin number 1008c2ecf20Sopenharmony_ci * @type: pin type, can be GLOBAL_CTRL_PIN/COMMON_PIN/MISC_PIN 1018c2ecf20Sopenharmony_ci * @reg: pin register address 1028c2ecf20Sopenharmony_ci * @bit_offset: bit offset in pin register 1038c2ecf20Sopenharmony_ci * @bit_width: bit width in pin register 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistruct sprd_pin { 1068c2ecf20Sopenharmony_ci const char *name; 1078c2ecf20Sopenharmony_ci unsigned int number; 1088c2ecf20Sopenharmony_ci enum pin_type type; 1098c2ecf20Sopenharmony_ci unsigned long reg; 1108c2ecf20Sopenharmony_ci unsigned long bit_offset; 1118c2ecf20Sopenharmony_ci unsigned long bit_width; 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/** 1158c2ecf20Sopenharmony_ci * struct sprd_pin_group: represent one group's description 1168c2ecf20Sopenharmony_ci * @name: group name 1178c2ecf20Sopenharmony_ci * @npins: pin numbers of this group 1188c2ecf20Sopenharmony_ci * @pins: pointer to pins array 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_cistruct sprd_pin_group { 1218c2ecf20Sopenharmony_ci const char *name; 1228c2ecf20Sopenharmony_ci unsigned int npins; 1238c2ecf20Sopenharmony_ci unsigned int *pins; 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/** 1278c2ecf20Sopenharmony_ci * struct sprd_pinctrl_soc_info: represent the SoC's pins description 1288c2ecf20Sopenharmony_ci * @groups: pointer to groups of pins 1298c2ecf20Sopenharmony_ci * @ngroups: group numbers of the whole SoC 1308c2ecf20Sopenharmony_ci * @pins: pointer to pins description 1318c2ecf20Sopenharmony_ci * @npins: pin numbers of the whole SoC 1328c2ecf20Sopenharmony_ci * @grp_names: pointer to group names array 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistruct sprd_pinctrl_soc_info { 1358c2ecf20Sopenharmony_ci struct sprd_pin_group *groups; 1368c2ecf20Sopenharmony_ci unsigned int ngroups; 1378c2ecf20Sopenharmony_ci struct sprd_pin *pins; 1388c2ecf20Sopenharmony_ci unsigned int npins; 1398c2ecf20Sopenharmony_ci const char **grp_names; 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/** 1438c2ecf20Sopenharmony_ci * struct sprd_pinctrl: represent the pin controller device 1448c2ecf20Sopenharmony_ci * @dev: pointer to the device structure 1458c2ecf20Sopenharmony_ci * @pctl: pointer to the pinctrl handle 1468c2ecf20Sopenharmony_ci * @base: base address of the controller 1478c2ecf20Sopenharmony_ci * @info: pointer to SoC's pins description information 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistruct sprd_pinctrl { 1508c2ecf20Sopenharmony_ci struct device *dev; 1518c2ecf20Sopenharmony_ci struct pinctrl_dev *pctl; 1528c2ecf20Sopenharmony_ci void __iomem *base; 1538c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info; 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#define SPRD_PIN_CONFIG_CONTROL (PIN_CONFIG_END + 1) 1578c2ecf20Sopenharmony_ci#define SPRD_PIN_CONFIG_SLEEP_MODE (PIN_CONFIG_END + 2) 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic int sprd_pinctrl_get_id_by_name(struct sprd_pinctrl *sprd_pctl, 1608c2ecf20Sopenharmony_ci const char *name) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 1638c2ecf20Sopenharmony_ci int i; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci for (i = 0; i < info->npins; i++) { 1668c2ecf20Sopenharmony_ci if (!strcmp(info->pins[i].name, name)) 1678c2ecf20Sopenharmony_ci return info->pins[i].number; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return -ENODEV; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic struct sprd_pin * 1748c2ecf20Sopenharmony_cisprd_pinctrl_get_pin_by_id(struct sprd_pinctrl *sprd_pctl, unsigned int id) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 1778c2ecf20Sopenharmony_ci struct sprd_pin *pin = NULL; 1788c2ecf20Sopenharmony_ci int i; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci for (i = 0; i < info->npins; i++) { 1818c2ecf20Sopenharmony_ci if (info->pins[i].number == id) { 1828c2ecf20Sopenharmony_ci pin = &info->pins[i]; 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return pin; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic const struct sprd_pin_group * 1918c2ecf20Sopenharmony_cisprd_pinctrl_find_group_by_name(struct sprd_pinctrl *sprd_pctl, 1928c2ecf20Sopenharmony_ci const char *name) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 1958c2ecf20Sopenharmony_ci const struct sprd_pin_group *grp = NULL; 1968c2ecf20Sopenharmony_ci int i; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci for (i = 0; i < info->ngroups; i++) { 1998c2ecf20Sopenharmony_ci if (!strcmp(info->groups[i].name, name)) { 2008c2ecf20Sopenharmony_ci grp = &info->groups[i]; 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return grp; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int sprd_pctrl_group_count(struct pinctrl_dev *pctldev) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 2118c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = pctl->info; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return info->ngroups; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic const char *sprd_pctrl_group_name(struct pinctrl_dev *pctldev, 2178c2ecf20Sopenharmony_ci unsigned int selector) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 2208c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = pctl->info; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return info->groups[selector].name; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int sprd_pctrl_group_pins(struct pinctrl_dev *pctldev, 2268c2ecf20Sopenharmony_ci unsigned int selector, 2278c2ecf20Sopenharmony_ci const unsigned int **pins, 2288c2ecf20Sopenharmony_ci unsigned int *npins) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 2318c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = pctl->info; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (selector >= info->ngroups) 2348c2ecf20Sopenharmony_ci return -EINVAL; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci *pins = info->groups[selector].pins; 2378c2ecf20Sopenharmony_ci *npins = info->groups[selector].npins; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int sprd_dt_node_to_map(struct pinctrl_dev *pctldev, 2438c2ecf20Sopenharmony_ci struct device_node *np, 2448c2ecf20Sopenharmony_ci struct pinctrl_map **map, 2458c2ecf20Sopenharmony_ci unsigned int *num_maps) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 2488c2ecf20Sopenharmony_ci const struct sprd_pin_group *grp; 2498c2ecf20Sopenharmony_ci unsigned long *configs = NULL; 2508c2ecf20Sopenharmony_ci unsigned int num_configs = 0; 2518c2ecf20Sopenharmony_ci unsigned int reserved_maps = 0; 2528c2ecf20Sopenharmony_ci unsigned int reserve = 0; 2538c2ecf20Sopenharmony_ci const char *function; 2548c2ecf20Sopenharmony_ci enum pinctrl_map_type type; 2558c2ecf20Sopenharmony_ci int ret; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci grp = sprd_pinctrl_find_group_by_name(pctl, np->name); 2588c2ecf20Sopenharmony_ci if (!grp) { 2598c2ecf20Sopenharmony_ci dev_err(pctl->dev, "unable to find group for node %s\n", 2608c2ecf20Sopenharmony_ci of_node_full_name(np)); 2618c2ecf20Sopenharmony_ci return -EINVAL; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci ret = of_property_count_strings(np, "pins"); 2658c2ecf20Sopenharmony_ci if (ret < 0) 2668c2ecf20Sopenharmony_ci return ret; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (ret == 1) 2698c2ecf20Sopenharmony_ci type = PIN_MAP_TYPE_CONFIGS_PIN; 2708c2ecf20Sopenharmony_ci else 2718c2ecf20Sopenharmony_ci type = PIN_MAP_TYPE_CONFIGS_GROUP; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci ret = of_property_read_string(np, "function", &function); 2748c2ecf20Sopenharmony_ci if (ret < 0) { 2758c2ecf20Sopenharmony_ci if (ret != -EINVAL) 2768c2ecf20Sopenharmony_ci dev_err(pctl->dev, 2778c2ecf20Sopenharmony_ci "%s: could not parse property function\n", 2788c2ecf20Sopenharmony_ci of_node_full_name(np)); 2798c2ecf20Sopenharmony_ci function = NULL; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, 2838c2ecf20Sopenharmony_ci &num_configs); 2848c2ecf20Sopenharmony_ci if (ret < 0) { 2858c2ecf20Sopenharmony_ci dev_err(pctl->dev, "%s: could not parse node property\n", 2868c2ecf20Sopenharmony_ci of_node_full_name(np)); 2878c2ecf20Sopenharmony_ci return ret; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci *map = NULL; 2918c2ecf20Sopenharmony_ci *num_maps = 0; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (function != NULL) 2948c2ecf20Sopenharmony_ci reserve++; 2958c2ecf20Sopenharmony_ci if (num_configs) 2968c2ecf20Sopenharmony_ci reserve++; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, 2998c2ecf20Sopenharmony_ci num_maps, reserve); 3008c2ecf20Sopenharmony_ci if (ret < 0) 3018c2ecf20Sopenharmony_ci goto out; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (function) { 3048c2ecf20Sopenharmony_ci ret = pinctrl_utils_add_map_mux(pctldev, map, 3058c2ecf20Sopenharmony_ci &reserved_maps, num_maps, 3068c2ecf20Sopenharmony_ci grp->name, function); 3078c2ecf20Sopenharmony_ci if (ret < 0) 3088c2ecf20Sopenharmony_ci goto out; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (num_configs) { 3128c2ecf20Sopenharmony_ci const char *group_or_pin; 3138c2ecf20Sopenharmony_ci unsigned int pin_id; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (type == PIN_MAP_TYPE_CONFIGS_PIN) { 3168c2ecf20Sopenharmony_ci pin_id = grp->pins[0]; 3178c2ecf20Sopenharmony_ci group_or_pin = pin_get_name(pctldev, pin_id); 3188c2ecf20Sopenharmony_ci } else { 3198c2ecf20Sopenharmony_ci group_or_pin = grp->name; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci ret = pinctrl_utils_add_map_configs(pctldev, map, 3238c2ecf20Sopenharmony_ci &reserved_maps, num_maps, 3248c2ecf20Sopenharmony_ci group_or_pin, configs, 3258c2ecf20Sopenharmony_ci num_configs, type); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ciout: 3298c2ecf20Sopenharmony_ci kfree(configs); 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic void sprd_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 3348c2ecf20Sopenharmony_ci unsigned int offset) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci seq_printf(s, "%s", dev_name(pctldev->dev)); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic const struct pinctrl_ops sprd_pctrl_ops = { 3408c2ecf20Sopenharmony_ci .get_groups_count = sprd_pctrl_group_count, 3418c2ecf20Sopenharmony_ci .get_group_name = sprd_pctrl_group_name, 3428c2ecf20Sopenharmony_ci .get_group_pins = sprd_pctrl_group_pins, 3438c2ecf20Sopenharmony_ci .pin_dbg_show = sprd_pctrl_dbg_show, 3448c2ecf20Sopenharmony_ci .dt_node_to_map = sprd_dt_node_to_map, 3458c2ecf20Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int sprd_pmx_get_function_count(struct pinctrl_dev *pctldev) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci return PIN_FUNC_MAX; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic const char *sprd_pmx_get_function_name(struct pinctrl_dev *pctldev, 3548c2ecf20Sopenharmony_ci unsigned int selector) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci switch (selector) { 3578c2ecf20Sopenharmony_ci case PIN_FUNC_1: 3588c2ecf20Sopenharmony_ci return "func1"; 3598c2ecf20Sopenharmony_ci case PIN_FUNC_2: 3608c2ecf20Sopenharmony_ci return "func2"; 3618c2ecf20Sopenharmony_ci case PIN_FUNC_3: 3628c2ecf20Sopenharmony_ci return "func3"; 3638c2ecf20Sopenharmony_ci case PIN_FUNC_4: 3648c2ecf20Sopenharmony_ci return "func4"; 3658c2ecf20Sopenharmony_ci default: 3668c2ecf20Sopenharmony_ci return "null"; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int sprd_pmx_get_function_groups(struct pinctrl_dev *pctldev, 3718c2ecf20Sopenharmony_ci unsigned int selector, 3728c2ecf20Sopenharmony_ci const char * const **groups, 3738c2ecf20Sopenharmony_ci unsigned int * const num_groups) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 3768c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = pctl->info; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci *groups = info->grp_names; 3798c2ecf20Sopenharmony_ci *num_groups = info->ngroups; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int sprd_pmx_set_mux(struct pinctrl_dev *pctldev, 3858c2ecf20Sopenharmony_ci unsigned int func_selector, 3868c2ecf20Sopenharmony_ci unsigned int group_selector) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 3898c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = pctl->info; 3908c2ecf20Sopenharmony_ci struct sprd_pin_group *grp = &info->groups[group_selector]; 3918c2ecf20Sopenharmony_ci unsigned int i, grp_pins = grp->npins; 3928c2ecf20Sopenharmony_ci unsigned long reg; 3938c2ecf20Sopenharmony_ci unsigned int val = 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (group_selector >= info->ngroups) 3968c2ecf20Sopenharmony_ci return -EINVAL; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci switch (func_selector) { 3998c2ecf20Sopenharmony_ci case PIN_FUNC_1: 4008c2ecf20Sopenharmony_ci val &= PIN_FUNC_SEL_1; 4018c2ecf20Sopenharmony_ci break; 4028c2ecf20Sopenharmony_ci case PIN_FUNC_2: 4038c2ecf20Sopenharmony_ci val |= PIN_FUNC_SEL_2; 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci case PIN_FUNC_3: 4068c2ecf20Sopenharmony_ci val |= PIN_FUNC_SEL_3; 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci case PIN_FUNC_4: 4098c2ecf20Sopenharmony_ci val |= PIN_FUNC_SEL_4; 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci default: 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci for (i = 0; i < grp_pins; i++) { 4168c2ecf20Sopenharmony_ci unsigned int pin_id = grp->pins[i]; 4178c2ecf20Sopenharmony_ci struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (!pin || pin->type != COMMON_PIN) 4208c2ecf20Sopenharmony_ci continue; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci reg = readl((void __iomem *)pin->reg); 4238c2ecf20Sopenharmony_ci reg &= ~PIN_FUNC_MASK; 4248c2ecf20Sopenharmony_ci reg |= val; 4258c2ecf20Sopenharmony_ci writel(reg, (void __iomem *)pin->reg); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic const struct pinmux_ops sprd_pmx_ops = { 4328c2ecf20Sopenharmony_ci .get_functions_count = sprd_pmx_get_function_count, 4338c2ecf20Sopenharmony_ci .get_function_name = sprd_pmx_get_function_name, 4348c2ecf20Sopenharmony_ci .get_function_groups = sprd_pmx_get_function_groups, 4358c2ecf20Sopenharmony_ci .set_mux = sprd_pmx_set_mux, 4368c2ecf20Sopenharmony_ci}; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic int sprd_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin_id, 4398c2ecf20Sopenharmony_ci unsigned long *config) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 4428c2ecf20Sopenharmony_ci struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 4438c2ecf20Sopenharmony_ci unsigned int param = pinconf_to_config_param(*config); 4448c2ecf20Sopenharmony_ci unsigned int reg, arg; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (!pin) 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (pin->type == GLOBAL_CTRL_PIN) { 4508c2ecf20Sopenharmony_ci reg = (readl((void __iomem *)pin->reg) >> 4518c2ecf20Sopenharmony_ci pin->bit_offset) & PINCTRL_BIT_MASK(pin->bit_width); 4528c2ecf20Sopenharmony_ci } else { 4538c2ecf20Sopenharmony_ci reg = readl((void __iomem *)pin->reg); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (pin->type == GLOBAL_CTRL_PIN && 4578c2ecf20Sopenharmony_ci param == SPRD_PIN_CONFIG_CONTROL) { 4588c2ecf20Sopenharmony_ci arg = reg; 4598c2ecf20Sopenharmony_ci } else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) { 4608c2ecf20Sopenharmony_ci switch (param) { 4618c2ecf20Sopenharmony_ci case SPRD_PIN_CONFIG_SLEEP_MODE: 4628c2ecf20Sopenharmony_ci arg = (reg >> SLEEP_MODE_SHIFT) & SLEEP_MODE_MASK; 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 4658c2ecf20Sopenharmony_ci arg = (reg >> SLEEP_INPUT_SHIFT) & SLEEP_INPUT_MASK; 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT_ENABLE: 4688c2ecf20Sopenharmony_ci arg = reg & SLEEP_OUTPUT_MASK; 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 4718c2ecf20Sopenharmony_ci if ((reg & SLEEP_OUTPUT) || (reg & SLEEP_INPUT)) 4728c2ecf20Sopenharmony_ci return -EINVAL; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci arg = 1; 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 4778c2ecf20Sopenharmony_ci arg = (reg >> DRIVE_STRENGTH_SHIFT) & 4788c2ecf20Sopenharmony_ci DRIVE_STRENGTH_MASK; 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 4818c2ecf20Sopenharmony_ci /* combine sleep pull down and pull down config */ 4828c2ecf20Sopenharmony_ci arg = ((reg >> SLEEP_PULL_DOWN_SHIFT) & 4838c2ecf20Sopenharmony_ci SLEEP_PULL_DOWN_MASK) << 16; 4848c2ecf20Sopenharmony_ci arg |= (reg >> PULL_DOWN_SHIFT) & PULL_DOWN_MASK; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 4878c2ecf20Sopenharmony_ci arg = (reg >> INPUT_SCHMITT_SHIFT) & INPUT_SCHMITT_MASK; 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 4908c2ecf20Sopenharmony_ci /* combine sleep pull up and pull up config */ 4918c2ecf20Sopenharmony_ci arg = ((reg >> SLEEP_PULL_UP_SHIFT) & 4928c2ecf20Sopenharmony_ci SLEEP_PULL_UP_MASK) << 16; 4938c2ecf20Sopenharmony_ci arg |= (reg >> PULL_UP_SHIFT) & PULL_UP_MASK; 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 4968c2ecf20Sopenharmony_ci if ((reg & (SLEEP_PULL_DOWN | SLEEP_PULL_UP)) || 4978c2ecf20Sopenharmony_ci (reg & (PULL_DOWN | PULL_UP_4_7K | PULL_UP_20K))) 4988c2ecf20Sopenharmony_ci return -EINVAL; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci arg = 1; 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci case PIN_CONFIG_SLEEP_HARDWARE_STATE: 5038c2ecf20Sopenharmony_ci arg = 0; 5048c2ecf20Sopenharmony_ci break; 5058c2ecf20Sopenharmony_ci default: 5068c2ecf20Sopenharmony_ci return -ENOTSUPP; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci } else { 5098c2ecf20Sopenharmony_ci return -ENOTSUPP; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 5138c2ecf20Sopenharmony_ci return 0; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic unsigned int sprd_pinconf_drive(unsigned int mA) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci unsigned int val = 0; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci switch (mA) { 5218c2ecf20Sopenharmony_ci case 2: 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci case 4: 5248c2ecf20Sopenharmony_ci val |= BIT(19); 5258c2ecf20Sopenharmony_ci break; 5268c2ecf20Sopenharmony_ci case 6: 5278c2ecf20Sopenharmony_ci val |= BIT(20); 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci case 8: 5308c2ecf20Sopenharmony_ci val |= BIT(19) | BIT(20); 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci case 10: 5338c2ecf20Sopenharmony_ci val |= BIT(21); 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci case 12: 5368c2ecf20Sopenharmony_ci val |= BIT(21) | BIT(19); 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci case 14: 5398c2ecf20Sopenharmony_ci val |= BIT(21) | BIT(20); 5408c2ecf20Sopenharmony_ci break; 5418c2ecf20Sopenharmony_ci case 16: 5428c2ecf20Sopenharmony_ci val |= BIT(19) | BIT(20) | BIT(21); 5438c2ecf20Sopenharmony_ci break; 5448c2ecf20Sopenharmony_ci case 20: 5458c2ecf20Sopenharmony_ci val |= BIT(22); 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci case 21: 5488c2ecf20Sopenharmony_ci val |= BIT(22) | BIT(19); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci case 24: 5518c2ecf20Sopenharmony_ci val |= BIT(22) | BIT(20); 5528c2ecf20Sopenharmony_ci break; 5538c2ecf20Sopenharmony_ci case 25: 5548c2ecf20Sopenharmony_ci val |= BIT(22) | BIT(20) | BIT(19); 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci case 27: 5578c2ecf20Sopenharmony_ci val |= BIT(22) | BIT(21); 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci case 29: 5608c2ecf20Sopenharmony_ci val |= BIT(22) | BIT(21) | BIT(19); 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci case 31: 5638c2ecf20Sopenharmony_ci val |= BIT(22) | BIT(21) | BIT(20); 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci case 33: 5668c2ecf20Sopenharmony_ci val |= BIT(22) | BIT(21) | BIT(20) | BIT(19); 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci default: 5698c2ecf20Sopenharmony_ci break; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return val; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic bool sprd_pinctrl_check_sleep_config(unsigned long *configs, 5768c2ecf20Sopenharmony_ci unsigned int num_configs) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci unsigned int param; 5798c2ecf20Sopenharmony_ci int i; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 5828c2ecf20Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 5838c2ecf20Sopenharmony_ci if (param == PIN_CONFIG_SLEEP_HARDWARE_STATE) 5848c2ecf20Sopenharmony_ci return true; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci return false; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic int sprd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id, 5918c2ecf20Sopenharmony_ci unsigned long *configs, unsigned int num_configs) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 5948c2ecf20Sopenharmony_ci struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 5958c2ecf20Sopenharmony_ci bool is_sleep_config; 5968c2ecf20Sopenharmony_ci unsigned long reg; 5978c2ecf20Sopenharmony_ci int i; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (!pin) 6008c2ecf20Sopenharmony_ci return -EINVAL; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci is_sleep_config = sprd_pinctrl_check_sleep_config(configs, num_configs); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 6058c2ecf20Sopenharmony_ci unsigned int param, arg, shift, mask, val; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 6088c2ecf20Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci val = 0; 6118c2ecf20Sopenharmony_ci shift = 0; 6128c2ecf20Sopenharmony_ci mask = 0; 6138c2ecf20Sopenharmony_ci if (pin->type == GLOBAL_CTRL_PIN && 6148c2ecf20Sopenharmony_ci param == SPRD_PIN_CONFIG_CONTROL) { 6158c2ecf20Sopenharmony_ci val = arg; 6168c2ecf20Sopenharmony_ci } else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) { 6178c2ecf20Sopenharmony_ci switch (param) { 6188c2ecf20Sopenharmony_ci case SPRD_PIN_CONFIG_SLEEP_MODE: 6198c2ecf20Sopenharmony_ci if (arg & AP_SLEEP) 6208c2ecf20Sopenharmony_ci val |= AP_SLEEP_MODE; 6218c2ecf20Sopenharmony_ci if (arg & PUBCP_SLEEP) 6228c2ecf20Sopenharmony_ci val |= PUBCP_SLEEP_MODE; 6238c2ecf20Sopenharmony_ci if (arg & TGLDSP_SLEEP) 6248c2ecf20Sopenharmony_ci val |= TGLDSP_SLEEP_MODE; 6258c2ecf20Sopenharmony_ci if (arg & AGDSP_SLEEP) 6268c2ecf20Sopenharmony_ci val |= AGDSP_SLEEP_MODE; 6278c2ecf20Sopenharmony_ci if (arg & CM4_SLEEP) 6288c2ecf20Sopenharmony_ci val |= CM4_SLEEP_MODE; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci mask = SLEEP_MODE_MASK; 6318c2ecf20Sopenharmony_ci shift = SLEEP_MODE_SHIFT; 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 6348c2ecf20Sopenharmony_ci if (is_sleep_config == true) { 6358c2ecf20Sopenharmony_ci if (arg > 0) 6368c2ecf20Sopenharmony_ci val |= SLEEP_INPUT; 6378c2ecf20Sopenharmony_ci else 6388c2ecf20Sopenharmony_ci val &= ~SLEEP_INPUT; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci mask = SLEEP_INPUT_MASK; 6418c2ecf20Sopenharmony_ci shift = SLEEP_INPUT_SHIFT; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci break; 6448c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT_ENABLE: 6458c2ecf20Sopenharmony_ci if (is_sleep_config == true) { 6468c2ecf20Sopenharmony_ci if (arg > 0) 6478c2ecf20Sopenharmony_ci val |= SLEEP_OUTPUT; 6488c2ecf20Sopenharmony_ci else 6498c2ecf20Sopenharmony_ci val &= ~SLEEP_OUTPUT; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci mask = SLEEP_OUTPUT_MASK; 6528c2ecf20Sopenharmony_ci shift = SLEEP_OUTPUT_SHIFT; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 6568c2ecf20Sopenharmony_ci if (is_sleep_config == true) { 6578c2ecf20Sopenharmony_ci val = shift = 0; 6588c2ecf20Sopenharmony_ci mask = SLEEP_OUTPUT | SLEEP_INPUT; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 6628c2ecf20Sopenharmony_ci if (arg < 2 || arg > 60) 6638c2ecf20Sopenharmony_ci return -EINVAL; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci val = sprd_pinconf_drive(arg); 6668c2ecf20Sopenharmony_ci mask = DRIVE_STRENGTH_MASK; 6678c2ecf20Sopenharmony_ci shift = DRIVE_STRENGTH_SHIFT; 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 6708c2ecf20Sopenharmony_ci if (is_sleep_config == true) { 6718c2ecf20Sopenharmony_ci val |= SLEEP_PULL_DOWN; 6728c2ecf20Sopenharmony_ci mask = SLEEP_PULL_DOWN_MASK; 6738c2ecf20Sopenharmony_ci shift = SLEEP_PULL_DOWN_SHIFT; 6748c2ecf20Sopenharmony_ci } else { 6758c2ecf20Sopenharmony_ci val |= PULL_DOWN; 6768c2ecf20Sopenharmony_ci mask = PULL_DOWN_MASK; 6778c2ecf20Sopenharmony_ci shift = PULL_DOWN_SHIFT; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci break; 6808c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 6818c2ecf20Sopenharmony_ci if (arg > 0) 6828c2ecf20Sopenharmony_ci val |= INPUT_SCHMITT; 6838c2ecf20Sopenharmony_ci else 6848c2ecf20Sopenharmony_ci val &= ~INPUT_SCHMITT; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci mask = INPUT_SCHMITT_MASK; 6878c2ecf20Sopenharmony_ci shift = INPUT_SCHMITT_SHIFT; 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 6908c2ecf20Sopenharmony_ci if (is_sleep_config == true) { 6918c2ecf20Sopenharmony_ci val |= SLEEP_PULL_UP; 6928c2ecf20Sopenharmony_ci mask = SLEEP_PULL_UP_MASK; 6938c2ecf20Sopenharmony_ci shift = SLEEP_PULL_UP_SHIFT; 6948c2ecf20Sopenharmony_ci } else { 6958c2ecf20Sopenharmony_ci if (arg == 20000) 6968c2ecf20Sopenharmony_ci val |= PULL_UP_20K; 6978c2ecf20Sopenharmony_ci else if (arg == 4700) 6988c2ecf20Sopenharmony_ci val |= PULL_UP_4_7K; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci mask = PULL_UP_MASK; 7018c2ecf20Sopenharmony_ci shift = PULL_UP_SHIFT; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci break; 7048c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 7058c2ecf20Sopenharmony_ci if (is_sleep_config == true) { 7068c2ecf20Sopenharmony_ci val = shift = 0; 7078c2ecf20Sopenharmony_ci mask = SLEEP_PULL_DOWN | SLEEP_PULL_UP; 7088c2ecf20Sopenharmony_ci } else { 7098c2ecf20Sopenharmony_ci val = shift = 0; 7108c2ecf20Sopenharmony_ci mask = PULL_DOWN | PULL_UP_20K | 7118c2ecf20Sopenharmony_ci PULL_UP_4_7K; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci case PIN_CONFIG_SLEEP_HARDWARE_STATE: 7158c2ecf20Sopenharmony_ci continue; 7168c2ecf20Sopenharmony_ci default: 7178c2ecf20Sopenharmony_ci return -ENOTSUPP; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci } else { 7208c2ecf20Sopenharmony_ci return -ENOTSUPP; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (pin->type == GLOBAL_CTRL_PIN) { 7248c2ecf20Sopenharmony_ci reg = readl((void __iomem *)pin->reg); 7258c2ecf20Sopenharmony_ci reg &= ~(PINCTRL_BIT_MASK(pin->bit_width) 7268c2ecf20Sopenharmony_ci << pin->bit_offset); 7278c2ecf20Sopenharmony_ci reg |= (val & PINCTRL_BIT_MASK(pin->bit_width)) 7288c2ecf20Sopenharmony_ci << pin->bit_offset; 7298c2ecf20Sopenharmony_ci writel(reg, (void __iomem *)pin->reg); 7308c2ecf20Sopenharmony_ci } else { 7318c2ecf20Sopenharmony_ci reg = readl((void __iomem *)pin->reg); 7328c2ecf20Sopenharmony_ci reg &= ~(mask << shift); 7338c2ecf20Sopenharmony_ci reg |= val; 7348c2ecf20Sopenharmony_ci writel(reg, (void __iomem *)pin->reg); 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return 0; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic int sprd_pinconf_group_get(struct pinctrl_dev *pctldev, 7428c2ecf20Sopenharmony_ci unsigned int selector, unsigned long *config) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7458c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = pctl->info; 7468c2ecf20Sopenharmony_ci struct sprd_pin_group *grp; 7478c2ecf20Sopenharmony_ci unsigned int pin_id; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (selector >= info->ngroups) 7508c2ecf20Sopenharmony_ci return -EINVAL; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci grp = &info->groups[selector]; 7538c2ecf20Sopenharmony_ci pin_id = grp->pins[0]; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci return sprd_pinconf_get(pctldev, pin_id, config); 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic int sprd_pinconf_group_set(struct pinctrl_dev *pctldev, 7598c2ecf20Sopenharmony_ci unsigned int selector, 7608c2ecf20Sopenharmony_ci unsigned long *configs, 7618c2ecf20Sopenharmony_ci unsigned int num_configs) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7648c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = pctl->info; 7658c2ecf20Sopenharmony_ci struct sprd_pin_group *grp; 7668c2ecf20Sopenharmony_ci int ret, i; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (selector >= info->ngroups) 7698c2ecf20Sopenharmony_ci return -EINVAL; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci grp = &info->groups[selector]; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 7748c2ecf20Sopenharmony_ci unsigned int pin_id = grp->pins[i]; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci ret = sprd_pinconf_set(pctldev, pin_id, configs, num_configs); 7778c2ecf20Sopenharmony_ci if (ret) 7788c2ecf20Sopenharmony_ci return ret; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci return 0; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic int sprd_pinconf_get_config(struct pinctrl_dev *pctldev, 7858c2ecf20Sopenharmony_ci unsigned int pin_id, 7868c2ecf20Sopenharmony_ci unsigned long *config) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7898c2ecf20Sopenharmony_ci struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (!pin) 7928c2ecf20Sopenharmony_ci return -EINVAL; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (pin->type == GLOBAL_CTRL_PIN) { 7958c2ecf20Sopenharmony_ci *config = (readl((void __iomem *)pin->reg) >> 7968c2ecf20Sopenharmony_ci pin->bit_offset) & PINCTRL_BIT_MASK(pin->bit_width); 7978c2ecf20Sopenharmony_ci } else { 7988c2ecf20Sopenharmony_ci *config = readl((void __iomem *)pin->reg); 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return 0; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic void sprd_pinconf_dbg_show(struct pinctrl_dev *pctldev, 8058c2ecf20Sopenharmony_ci struct seq_file *s, unsigned int pin_id) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci unsigned long config; 8088c2ecf20Sopenharmony_ci int ret; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci ret = sprd_pinconf_get_config(pctldev, pin_id, &config); 8118c2ecf20Sopenharmony_ci if (ret) 8128c2ecf20Sopenharmony_ci return; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci seq_printf(s, "0x%lx", config); 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic void sprd_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, 8188c2ecf20Sopenharmony_ci struct seq_file *s, 8198c2ecf20Sopenharmony_ci unsigned int selector) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 8228c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = pctl->info; 8238c2ecf20Sopenharmony_ci struct sprd_pin_group *grp; 8248c2ecf20Sopenharmony_ci unsigned long config; 8258c2ecf20Sopenharmony_ci const char *name; 8268c2ecf20Sopenharmony_ci int i, ret; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (selector >= info->ngroups) 8298c2ecf20Sopenharmony_ci return; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci grp = &info->groups[selector]; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci seq_putc(s, '\n'); 8348c2ecf20Sopenharmony_ci for (i = 0; i < grp->npins; i++, config++) { 8358c2ecf20Sopenharmony_ci unsigned int pin_id = grp->pins[i]; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci name = pin_get_name(pctldev, pin_id); 8388c2ecf20Sopenharmony_ci ret = sprd_pinconf_get_config(pctldev, pin_id, &config); 8398c2ecf20Sopenharmony_ci if (ret) 8408c2ecf20Sopenharmony_ci return; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci seq_printf(s, "%s: 0x%lx ", name, config); 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic const struct pinconf_ops sprd_pinconf_ops = { 8478c2ecf20Sopenharmony_ci .is_generic = true, 8488c2ecf20Sopenharmony_ci .pin_config_get = sprd_pinconf_get, 8498c2ecf20Sopenharmony_ci .pin_config_set = sprd_pinconf_set, 8508c2ecf20Sopenharmony_ci .pin_config_group_get = sprd_pinconf_group_get, 8518c2ecf20Sopenharmony_ci .pin_config_group_set = sprd_pinconf_group_set, 8528c2ecf20Sopenharmony_ci .pin_config_dbg_show = sprd_pinconf_dbg_show, 8538c2ecf20Sopenharmony_ci .pin_config_group_dbg_show = sprd_pinconf_group_dbg_show, 8548c2ecf20Sopenharmony_ci}; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic const struct pinconf_generic_params sprd_dt_params[] = { 8578c2ecf20Sopenharmony_ci {"sprd,control", SPRD_PIN_CONFIG_CONTROL, 0}, 8588c2ecf20Sopenharmony_ci {"sprd,sleep-mode", SPRD_PIN_CONFIG_SLEEP_MODE, 0}, 8598c2ecf20Sopenharmony_ci}; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 8628c2ecf20Sopenharmony_cistatic const struct pin_config_item sprd_conf_items[] = { 8638c2ecf20Sopenharmony_ci PCONFDUMP(SPRD_PIN_CONFIG_CONTROL, "global control", NULL, true), 8648c2ecf20Sopenharmony_ci PCONFDUMP(SPRD_PIN_CONFIG_SLEEP_MODE, "sleep mode", NULL, true), 8658c2ecf20Sopenharmony_ci}; 8668c2ecf20Sopenharmony_ci#endif 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic struct pinctrl_desc sprd_pinctrl_desc = { 8698c2ecf20Sopenharmony_ci .pctlops = &sprd_pctrl_ops, 8708c2ecf20Sopenharmony_ci .pmxops = &sprd_pmx_ops, 8718c2ecf20Sopenharmony_ci .confops = &sprd_pinconf_ops, 8728c2ecf20Sopenharmony_ci .num_custom_params = ARRAY_SIZE(sprd_dt_params), 8738c2ecf20Sopenharmony_ci .custom_params = sprd_dt_params, 8748c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 8758c2ecf20Sopenharmony_ci .custom_conf_items = sprd_conf_items, 8768c2ecf20Sopenharmony_ci#endif 8778c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 8788c2ecf20Sopenharmony_ci}; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic int sprd_pinctrl_parse_groups(struct device_node *np, 8818c2ecf20Sopenharmony_ci struct sprd_pinctrl *sprd_pctl, 8828c2ecf20Sopenharmony_ci struct sprd_pin_group *grp) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct property *prop; 8858c2ecf20Sopenharmony_ci const char *pin_name; 8868c2ecf20Sopenharmony_ci int ret, i = 0; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci ret = of_property_count_strings(np, "pins"); 8898c2ecf20Sopenharmony_ci if (ret < 0) 8908c2ecf20Sopenharmony_ci return ret; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci grp->name = np->name; 8938c2ecf20Sopenharmony_ci grp->npins = ret; 8948c2ecf20Sopenharmony_ci grp->pins = devm_kcalloc(sprd_pctl->dev, 8958c2ecf20Sopenharmony_ci grp->npins, sizeof(unsigned int), 8968c2ecf20Sopenharmony_ci GFP_KERNEL); 8978c2ecf20Sopenharmony_ci if (!grp->pins) 8988c2ecf20Sopenharmony_ci return -ENOMEM; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci of_property_for_each_string(np, "pins", prop, pin_name) { 9018c2ecf20Sopenharmony_ci ret = sprd_pinctrl_get_id_by_name(sprd_pctl, pin_name); 9028c2ecf20Sopenharmony_ci if (ret >= 0) 9038c2ecf20Sopenharmony_ci grp->pins[i++] = ret; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 9078c2ecf20Sopenharmony_ci dev_dbg(sprd_pctl->dev, 9088c2ecf20Sopenharmony_ci "Group[%s] contains [%d] pins: id = %d\n", 9098c2ecf20Sopenharmony_ci grp->name, grp->npins, grp->pins[i]); 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci return 0; 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_cistatic unsigned int sprd_pinctrl_get_groups(struct device_node *np) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct device_node *child; 9188c2ecf20Sopenharmony_ci unsigned int group_cnt, cnt; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci group_cnt = of_get_child_count(np); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 9238c2ecf20Sopenharmony_ci cnt = of_get_child_count(child); 9248c2ecf20Sopenharmony_ci if (cnt > 0) 9258c2ecf20Sopenharmony_ci group_cnt += cnt; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci return group_cnt; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic int sprd_pinctrl_parse_dt(struct sprd_pinctrl *sprd_pctl) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 9348c2ecf20Sopenharmony_ci struct device_node *np = sprd_pctl->dev->of_node; 9358c2ecf20Sopenharmony_ci struct device_node *child, *sub_child; 9368c2ecf20Sopenharmony_ci struct sprd_pin_group *grp; 9378c2ecf20Sopenharmony_ci const char **temp; 9388c2ecf20Sopenharmony_ci int ret; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (!np) 9418c2ecf20Sopenharmony_ci return -ENODEV; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci info->ngroups = sprd_pinctrl_get_groups(np); 9448c2ecf20Sopenharmony_ci if (!info->ngroups) 9458c2ecf20Sopenharmony_ci return 0; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci info->groups = devm_kcalloc(sprd_pctl->dev, 9488c2ecf20Sopenharmony_ci info->ngroups, 9498c2ecf20Sopenharmony_ci sizeof(struct sprd_pin_group), 9508c2ecf20Sopenharmony_ci GFP_KERNEL); 9518c2ecf20Sopenharmony_ci if (!info->groups) 9528c2ecf20Sopenharmony_ci return -ENOMEM; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci info->grp_names = devm_kcalloc(sprd_pctl->dev, 9558c2ecf20Sopenharmony_ci info->ngroups, sizeof(char *), 9568c2ecf20Sopenharmony_ci GFP_KERNEL); 9578c2ecf20Sopenharmony_ci if (!info->grp_names) 9588c2ecf20Sopenharmony_ci return -ENOMEM; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci temp = info->grp_names; 9618c2ecf20Sopenharmony_ci grp = info->groups; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 9648c2ecf20Sopenharmony_ci ret = sprd_pinctrl_parse_groups(child, sprd_pctl, grp); 9658c2ecf20Sopenharmony_ci if (ret) { 9668c2ecf20Sopenharmony_ci of_node_put(child); 9678c2ecf20Sopenharmony_ci return ret; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci *temp++ = grp->name; 9718c2ecf20Sopenharmony_ci grp++; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (of_get_child_count(child) > 0) { 9748c2ecf20Sopenharmony_ci for_each_child_of_node(child, sub_child) { 9758c2ecf20Sopenharmony_ci ret = sprd_pinctrl_parse_groups(sub_child, 9768c2ecf20Sopenharmony_ci sprd_pctl, grp); 9778c2ecf20Sopenharmony_ci if (ret) { 9788c2ecf20Sopenharmony_ci of_node_put(sub_child); 9798c2ecf20Sopenharmony_ci of_node_put(child); 9808c2ecf20Sopenharmony_ci return ret; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci *temp++ = grp->name; 9848c2ecf20Sopenharmony_ci grp++; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci return 0; 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cistatic int sprd_pinctrl_add_pins(struct sprd_pinctrl *sprd_pctl, 9938c2ecf20Sopenharmony_ci struct sprd_pins_info *sprd_soc_pin_info, 9948c2ecf20Sopenharmony_ci int pins_cnt) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 9978c2ecf20Sopenharmony_ci unsigned int ctrl_pin = 0, com_pin = 0; 9988c2ecf20Sopenharmony_ci struct sprd_pin *pin; 9998c2ecf20Sopenharmony_ci int i; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci info->npins = pins_cnt; 10028c2ecf20Sopenharmony_ci info->pins = devm_kcalloc(sprd_pctl->dev, 10038c2ecf20Sopenharmony_ci info->npins, sizeof(struct sprd_pin), 10048c2ecf20Sopenharmony_ci GFP_KERNEL); 10058c2ecf20Sopenharmony_ci if (!info->pins) 10068c2ecf20Sopenharmony_ci return -ENOMEM; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci for (i = 0, pin = info->pins; i < info->npins; i++, pin++) { 10098c2ecf20Sopenharmony_ci unsigned int reg; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci pin->name = sprd_soc_pin_info[i].name; 10128c2ecf20Sopenharmony_ci pin->type = sprd_soc_pin_info[i].type; 10138c2ecf20Sopenharmony_ci pin->number = sprd_soc_pin_info[i].num; 10148c2ecf20Sopenharmony_ci reg = sprd_soc_pin_info[i].reg; 10158c2ecf20Sopenharmony_ci if (pin->type == GLOBAL_CTRL_PIN) { 10168c2ecf20Sopenharmony_ci pin->reg = (unsigned long)sprd_pctl->base + 10178c2ecf20Sopenharmony_ci PINCTRL_REG_LEN * reg; 10188c2ecf20Sopenharmony_ci pin->bit_offset = sprd_soc_pin_info[i].bit_offset; 10198c2ecf20Sopenharmony_ci pin->bit_width = sprd_soc_pin_info[i].bit_width; 10208c2ecf20Sopenharmony_ci ctrl_pin++; 10218c2ecf20Sopenharmony_ci } else if (pin->type == COMMON_PIN) { 10228c2ecf20Sopenharmony_ci pin->reg = (unsigned long)sprd_pctl->base + 10238c2ecf20Sopenharmony_ci PINCTRL_REG_OFFSET + PINCTRL_REG_LEN * 10248c2ecf20Sopenharmony_ci (i - ctrl_pin); 10258c2ecf20Sopenharmony_ci com_pin++; 10268c2ecf20Sopenharmony_ci } else if (pin->type == MISC_PIN) { 10278c2ecf20Sopenharmony_ci pin->reg = (unsigned long)sprd_pctl->base + 10288c2ecf20Sopenharmony_ci PINCTRL_REG_MISC_OFFSET + PINCTRL_REG_LEN * 10298c2ecf20Sopenharmony_ci (i - ctrl_pin - com_pin); 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci for (i = 0, pin = info->pins; i < info->npins; pin++, i++) { 10348c2ecf20Sopenharmony_ci dev_dbg(sprd_pctl->dev, "pin name[%s-%d], type = %d, " 10358c2ecf20Sopenharmony_ci "bit offset = %ld, bit width = %ld, reg = 0x%lx\n", 10368c2ecf20Sopenharmony_ci pin->name, pin->number, pin->type, 10378c2ecf20Sopenharmony_ci pin->bit_offset, pin->bit_width, pin->reg); 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return 0; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ciint sprd_pinctrl_core_probe(struct platform_device *pdev, 10448c2ecf20Sopenharmony_ci struct sprd_pins_info *sprd_soc_pin_info, 10458c2ecf20Sopenharmony_ci int pins_cnt) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct sprd_pinctrl *sprd_pctl; 10488c2ecf20Sopenharmony_ci struct sprd_pinctrl_soc_info *pinctrl_info; 10498c2ecf20Sopenharmony_ci struct pinctrl_pin_desc *pin_desc; 10508c2ecf20Sopenharmony_ci int ret, i; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci sprd_pctl = devm_kzalloc(&pdev->dev, sizeof(struct sprd_pinctrl), 10538c2ecf20Sopenharmony_ci GFP_KERNEL); 10548c2ecf20Sopenharmony_ci if (!sprd_pctl) 10558c2ecf20Sopenharmony_ci return -ENOMEM; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci sprd_pctl->base = devm_platform_ioremap_resource(pdev, 0); 10588c2ecf20Sopenharmony_ci if (IS_ERR(sprd_pctl->base)) 10598c2ecf20Sopenharmony_ci return PTR_ERR(sprd_pctl->base); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci pinctrl_info = devm_kzalloc(&pdev->dev, 10628c2ecf20Sopenharmony_ci sizeof(struct sprd_pinctrl_soc_info), 10638c2ecf20Sopenharmony_ci GFP_KERNEL); 10648c2ecf20Sopenharmony_ci if (!pinctrl_info) 10658c2ecf20Sopenharmony_ci return -ENOMEM; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci sprd_pctl->info = pinctrl_info; 10688c2ecf20Sopenharmony_ci sprd_pctl->dev = &pdev->dev; 10698c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, sprd_pctl); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci ret = sprd_pinctrl_add_pins(sprd_pctl, sprd_soc_pin_info, pins_cnt); 10728c2ecf20Sopenharmony_ci if (ret) { 10738c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "fail to add pins information\n"); 10748c2ecf20Sopenharmony_ci return ret; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci ret = sprd_pinctrl_parse_dt(sprd_pctl); 10788c2ecf20Sopenharmony_ci if (ret) { 10798c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "fail to parse dt properties\n"); 10808c2ecf20Sopenharmony_ci return ret; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci pin_desc = devm_kcalloc(&pdev->dev, 10848c2ecf20Sopenharmony_ci pinctrl_info->npins, 10858c2ecf20Sopenharmony_ci sizeof(struct pinctrl_pin_desc), 10868c2ecf20Sopenharmony_ci GFP_KERNEL); 10878c2ecf20Sopenharmony_ci if (!pin_desc) 10888c2ecf20Sopenharmony_ci return -ENOMEM; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci for (i = 0; i < pinctrl_info->npins; i++) { 10918c2ecf20Sopenharmony_ci pin_desc[i].number = pinctrl_info->pins[i].number; 10928c2ecf20Sopenharmony_ci pin_desc[i].name = pinctrl_info->pins[i].name; 10938c2ecf20Sopenharmony_ci pin_desc[i].drv_data = pinctrl_info; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci sprd_pinctrl_desc.pins = pin_desc; 10978c2ecf20Sopenharmony_ci sprd_pinctrl_desc.name = dev_name(&pdev->dev); 10988c2ecf20Sopenharmony_ci sprd_pinctrl_desc.npins = pinctrl_info->npins; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci sprd_pctl->pctl = pinctrl_register(&sprd_pinctrl_desc, 11018c2ecf20Sopenharmony_ci &pdev->dev, (void *)sprd_pctl); 11028c2ecf20Sopenharmony_ci if (IS_ERR(sprd_pctl->pctl)) { 11038c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not register pinctrl driver\n"); 11048c2ecf20Sopenharmony_ci return PTR_ERR(sprd_pctl->pctl); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci return 0; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sprd_pinctrl_core_probe); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ciint sprd_pinctrl_remove(struct platform_device *pdev) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci struct sprd_pinctrl *sprd_pctl = platform_get_drvdata(pdev); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci pinctrl_unregister(sprd_pctl->pctl); 11168c2ecf20Sopenharmony_ci return 0; 11178c2ecf20Sopenharmony_ci} 11188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sprd_pinctrl_remove); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_civoid sprd_pinctrl_shutdown(struct platform_device *pdev) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci struct pinctrl *pinctl; 11238c2ecf20Sopenharmony_ci struct pinctrl_state *state; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci pinctl = devm_pinctrl_get(&pdev->dev); 11268c2ecf20Sopenharmony_ci if (IS_ERR(pinctl)) 11278c2ecf20Sopenharmony_ci return; 11288c2ecf20Sopenharmony_ci state = pinctrl_lookup_state(pinctl, "shutdown"); 11298c2ecf20Sopenharmony_ci if (IS_ERR(state)) 11308c2ecf20Sopenharmony_ci return; 11318c2ecf20Sopenharmony_ci pinctrl_select_state(pinctl, state); 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sprd_pinctrl_shutdown); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SPREADTRUM Pin Controller Driver"); 11368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>"); 11378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1138