11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 241d32cfcSBaolin Wang /* 341d32cfcSBaolin Wang * Spreadtrum pin controller driver 441d32cfcSBaolin Wang * Copyright (C) 2017 Spreadtrum - http://www.spreadtrum.com 541d32cfcSBaolin Wang */ 641d32cfcSBaolin Wang 741d32cfcSBaolin Wang #include <linux/debugfs.h> 841d32cfcSBaolin Wang #include <linux/err.h> 941d32cfcSBaolin Wang #include <linux/init.h> 1041d32cfcSBaolin Wang #include <linux/io.h> 1141d32cfcSBaolin Wang #include <linux/kernel.h> 1241d32cfcSBaolin Wang #include <linux/module.h> 1341d32cfcSBaolin Wang #include <linux/of.h> 1441d32cfcSBaolin Wang #include <linux/of_device.h> 1541d32cfcSBaolin Wang #include <linux/platform_device.h> 1641d32cfcSBaolin Wang #include <linux/pinctrl/machine.h> 1741d32cfcSBaolin Wang #include <linux/pinctrl/pinconf.h> 1841d32cfcSBaolin Wang #include <linux/pinctrl/pinconf-generic.h> 1941d32cfcSBaolin Wang #include <linux/pinctrl/pinctrl.h> 2041d32cfcSBaolin Wang #include <linux/pinctrl/pinmux.h> 2141d32cfcSBaolin Wang #include <linux/slab.h> 2241d32cfcSBaolin Wang 2341d32cfcSBaolin Wang #include "../core.h" 2441d32cfcSBaolin Wang #include "../pinmux.h" 2541d32cfcSBaolin Wang #include "../pinconf.h" 2641d32cfcSBaolin Wang #include "../pinctrl-utils.h" 2741d32cfcSBaolin Wang #include "pinctrl-sprd.h" 2841d32cfcSBaolin Wang 2941d32cfcSBaolin Wang #define PINCTRL_BIT_MASK(width) (~(~0UL << (width))) 3041d32cfcSBaolin Wang #define PINCTRL_REG_OFFSET 0x20 3141d32cfcSBaolin Wang #define PINCTRL_REG_MISC_OFFSET 0x4020 3241d32cfcSBaolin Wang #define PINCTRL_REG_LEN 0x4 3341d32cfcSBaolin Wang 3441d32cfcSBaolin Wang #define PIN_FUNC_MASK (BIT(4) | BIT(5)) 3541d32cfcSBaolin Wang #define PIN_FUNC_SEL_1 ~PIN_FUNC_MASK 3641d32cfcSBaolin Wang #define PIN_FUNC_SEL_2 BIT(4) 3741d32cfcSBaolin Wang #define PIN_FUNC_SEL_3 BIT(5) 3841d32cfcSBaolin Wang #define PIN_FUNC_SEL_4 PIN_FUNC_MASK 3941d32cfcSBaolin Wang 4041d32cfcSBaolin Wang #define AP_SLEEP_MODE BIT(13) 4141d32cfcSBaolin Wang #define PUBCP_SLEEP_MODE BIT(14) 4241d32cfcSBaolin Wang #define TGLDSP_SLEEP_MODE BIT(15) 4341d32cfcSBaolin Wang #define AGDSP_SLEEP_MODE BIT(16) 44*e543b3f5SBruce Chen #define CM4_SLEEP_MODE BIT(17) 45*e543b3f5SBruce Chen #define SLEEP_MODE_MASK GENMASK(5, 0) 4641d32cfcSBaolin Wang #define SLEEP_MODE_SHIFT 13 4741d32cfcSBaolin Wang 4841d32cfcSBaolin Wang #define SLEEP_INPUT BIT(1) 4941d32cfcSBaolin Wang #define SLEEP_INPUT_MASK 0x1 5041d32cfcSBaolin Wang #define SLEEP_INPUT_SHIFT 1 5141d32cfcSBaolin Wang 5241d32cfcSBaolin Wang #define SLEEP_OUTPUT BIT(0) 5341d32cfcSBaolin Wang #define SLEEP_OUTPUT_MASK 0x1 5441d32cfcSBaolin Wang #define SLEEP_OUTPUT_SHIFT 0 5541d32cfcSBaolin Wang 5641d32cfcSBaolin Wang #define DRIVE_STRENGTH_MASK GENMASK(3, 0) 5741d32cfcSBaolin Wang #define DRIVE_STRENGTH_SHIFT 19 5841d32cfcSBaolin Wang 5941d32cfcSBaolin Wang #define SLEEP_PULL_DOWN BIT(2) 6041d32cfcSBaolin Wang #define SLEEP_PULL_DOWN_MASK 0x1 6141d32cfcSBaolin Wang #define SLEEP_PULL_DOWN_SHIFT 2 6241d32cfcSBaolin Wang 6341d32cfcSBaolin Wang #define PULL_DOWN BIT(6) 6441d32cfcSBaolin Wang #define PULL_DOWN_MASK 0x1 6541d32cfcSBaolin Wang #define PULL_DOWN_SHIFT 6 6641d32cfcSBaolin Wang 6741d32cfcSBaolin Wang #define SLEEP_PULL_UP BIT(3) 6841d32cfcSBaolin Wang #define SLEEP_PULL_UP_MASK 0x1 6941d32cfcSBaolin Wang #define SLEEP_PULL_UP_SHIFT 3 7041d32cfcSBaolin Wang 7141d32cfcSBaolin Wang #define PULL_UP_20K (BIT(12) | BIT(7)) 7241d32cfcSBaolin Wang #define PULL_UP_4_7K BIT(12) 7341d32cfcSBaolin Wang #define PULL_UP_MASK 0x21 7441d32cfcSBaolin Wang #define PULL_UP_SHIFT 7 7541d32cfcSBaolin Wang 7641d32cfcSBaolin Wang #define INPUT_SCHMITT BIT(11) 7741d32cfcSBaolin Wang #define INPUT_SCHMITT_MASK 0x1 7841d32cfcSBaolin Wang #define INPUT_SCHMITT_SHIFT 11 7941d32cfcSBaolin Wang 8041d32cfcSBaolin Wang enum pin_sleep_mode { 8141d32cfcSBaolin Wang AP_SLEEP = BIT(0), 8241d32cfcSBaolin Wang PUBCP_SLEEP = BIT(1), 8341d32cfcSBaolin Wang TGLDSP_SLEEP = BIT(2), 8441d32cfcSBaolin Wang AGDSP_SLEEP = BIT(3), 85*e543b3f5SBruce Chen CM4_SLEEP = BIT(4), 8641d32cfcSBaolin Wang }; 8741d32cfcSBaolin Wang 8841d32cfcSBaolin Wang enum pin_func_sel { 8941d32cfcSBaolin Wang PIN_FUNC_1, 9041d32cfcSBaolin Wang PIN_FUNC_2, 9141d32cfcSBaolin Wang PIN_FUNC_3, 9241d32cfcSBaolin Wang PIN_FUNC_4, 9341d32cfcSBaolin Wang PIN_FUNC_MAX, 9441d32cfcSBaolin Wang }; 9541d32cfcSBaolin Wang 9641d32cfcSBaolin Wang /** 9741d32cfcSBaolin Wang * struct sprd_pin: represent one pin's description 9841d32cfcSBaolin Wang * @name: pin name 9941d32cfcSBaolin Wang * @number: pin number 10041d32cfcSBaolin Wang * @type: pin type, can be GLOBAL_CTRL_PIN/COMMON_PIN/MISC_PIN 10141d32cfcSBaolin Wang * @reg: pin register address 10241d32cfcSBaolin Wang * @bit_offset: bit offset in pin register 10341d32cfcSBaolin Wang * @bit_width: bit width in pin register 10441d32cfcSBaolin Wang */ 10541d32cfcSBaolin Wang struct sprd_pin { 10641d32cfcSBaolin Wang const char *name; 10741d32cfcSBaolin Wang unsigned int number; 10841d32cfcSBaolin Wang enum pin_type type; 10941d32cfcSBaolin Wang unsigned long reg; 11041d32cfcSBaolin Wang unsigned long bit_offset; 11141d32cfcSBaolin Wang unsigned long bit_width; 11241d32cfcSBaolin Wang }; 11341d32cfcSBaolin Wang 11441d32cfcSBaolin Wang /** 11541d32cfcSBaolin Wang * struct sprd_pin_group: represent one group's description 11641d32cfcSBaolin Wang * @name: group name 11741d32cfcSBaolin Wang * @npins: pin numbers of this group 11841d32cfcSBaolin Wang * @pins: pointer to pins array 11941d32cfcSBaolin Wang */ 12041d32cfcSBaolin Wang struct sprd_pin_group { 12141d32cfcSBaolin Wang const char *name; 12241d32cfcSBaolin Wang unsigned int npins; 12341d32cfcSBaolin Wang unsigned int *pins; 12441d32cfcSBaolin Wang }; 12541d32cfcSBaolin Wang 12641d32cfcSBaolin Wang /** 12741d32cfcSBaolin Wang * struct sprd_pinctrl_soc_info: represent the SoC's pins description 12841d32cfcSBaolin Wang * @groups: pointer to groups of pins 12941d32cfcSBaolin Wang * @ngroups: group numbers of the whole SoC 13041d32cfcSBaolin Wang * @pins: pointer to pins description 13141d32cfcSBaolin Wang * @npins: pin numbers of the whole SoC 13241d32cfcSBaolin Wang * @grp_names: pointer to group names array 13341d32cfcSBaolin Wang */ 13441d32cfcSBaolin Wang struct sprd_pinctrl_soc_info { 13541d32cfcSBaolin Wang struct sprd_pin_group *groups; 13641d32cfcSBaolin Wang unsigned int ngroups; 13741d32cfcSBaolin Wang struct sprd_pin *pins; 13841d32cfcSBaolin Wang unsigned int npins; 13941d32cfcSBaolin Wang const char **grp_names; 14041d32cfcSBaolin Wang }; 14141d32cfcSBaolin Wang 14241d32cfcSBaolin Wang /** 14341d32cfcSBaolin Wang * struct sprd_pinctrl: represent the pin controller device 14441d32cfcSBaolin Wang * @dev: pointer to the device structure 14541d32cfcSBaolin Wang * @pctl: pointer to the pinctrl handle 14641d32cfcSBaolin Wang * @base: base address of the controller 14741d32cfcSBaolin Wang * @info: pointer to SoC's pins description information 14841d32cfcSBaolin Wang */ 14941d32cfcSBaolin Wang struct sprd_pinctrl { 15041d32cfcSBaolin Wang struct device *dev; 15141d32cfcSBaolin Wang struct pinctrl_dev *pctl; 15241d32cfcSBaolin Wang void __iomem *base; 15341d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info; 15441d32cfcSBaolin Wang }; 15541d32cfcSBaolin Wang 156957063c9SNathan Chancellor #define SPRD_PIN_CONFIG_CONTROL (PIN_CONFIG_END + 1) 157957063c9SNathan Chancellor #define SPRD_PIN_CONFIG_SLEEP_MODE (PIN_CONFIG_END + 2) 15841d32cfcSBaolin Wang 15941d32cfcSBaolin Wang static int sprd_pinctrl_get_id_by_name(struct sprd_pinctrl *sprd_pctl, 16041d32cfcSBaolin Wang const char *name) 16141d32cfcSBaolin Wang { 16241d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 16341d32cfcSBaolin Wang int i; 16441d32cfcSBaolin Wang 16541d32cfcSBaolin Wang for (i = 0; i < info->npins; i++) { 16641d32cfcSBaolin Wang if (!strcmp(info->pins[i].name, name)) 16741d32cfcSBaolin Wang return info->pins[i].number; 16841d32cfcSBaolin Wang } 16941d32cfcSBaolin Wang 17041d32cfcSBaolin Wang return -ENODEV; 17141d32cfcSBaolin Wang } 17241d32cfcSBaolin Wang 17341d32cfcSBaolin Wang static struct sprd_pin * 17441d32cfcSBaolin Wang sprd_pinctrl_get_pin_by_id(struct sprd_pinctrl *sprd_pctl, unsigned int id) 17541d32cfcSBaolin Wang { 17641d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 17741d32cfcSBaolin Wang struct sprd_pin *pin = NULL; 17841d32cfcSBaolin Wang int i; 17941d32cfcSBaolin Wang 18041d32cfcSBaolin Wang for (i = 0; i < info->npins; i++) { 18141d32cfcSBaolin Wang if (info->pins[i].number == id) { 18241d32cfcSBaolin Wang pin = &info->pins[i]; 18341d32cfcSBaolin Wang break; 18441d32cfcSBaolin Wang } 18541d32cfcSBaolin Wang } 18641d32cfcSBaolin Wang 18741d32cfcSBaolin Wang return pin; 18841d32cfcSBaolin Wang } 18941d32cfcSBaolin Wang 19041d32cfcSBaolin Wang static const struct sprd_pin_group * 19141d32cfcSBaolin Wang sprd_pinctrl_find_group_by_name(struct sprd_pinctrl *sprd_pctl, 19241d32cfcSBaolin Wang const char *name) 19341d32cfcSBaolin Wang { 19441d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 19541d32cfcSBaolin Wang const struct sprd_pin_group *grp = NULL; 19641d32cfcSBaolin Wang int i; 19741d32cfcSBaolin Wang 19841d32cfcSBaolin Wang for (i = 0; i < info->ngroups; i++) { 19941d32cfcSBaolin Wang if (!strcmp(info->groups[i].name, name)) { 20041d32cfcSBaolin Wang grp = &info->groups[i]; 20141d32cfcSBaolin Wang break; 20241d32cfcSBaolin Wang } 20341d32cfcSBaolin Wang } 20441d32cfcSBaolin Wang 20541d32cfcSBaolin Wang return grp; 20641d32cfcSBaolin Wang } 20741d32cfcSBaolin Wang 20841d32cfcSBaolin Wang static int sprd_pctrl_group_count(struct pinctrl_dev *pctldev) 20941d32cfcSBaolin Wang { 21041d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 21141d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 21241d32cfcSBaolin Wang 21341d32cfcSBaolin Wang return info->ngroups; 21441d32cfcSBaolin Wang } 21541d32cfcSBaolin Wang 21641d32cfcSBaolin Wang static const char *sprd_pctrl_group_name(struct pinctrl_dev *pctldev, 21741d32cfcSBaolin Wang unsigned int selector) 21841d32cfcSBaolin Wang { 21941d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 22041d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 22141d32cfcSBaolin Wang 22241d32cfcSBaolin Wang return info->groups[selector].name; 22341d32cfcSBaolin Wang } 22441d32cfcSBaolin Wang 22541d32cfcSBaolin Wang static int sprd_pctrl_group_pins(struct pinctrl_dev *pctldev, 22641d32cfcSBaolin Wang unsigned int selector, 22741d32cfcSBaolin Wang const unsigned int **pins, 22841d32cfcSBaolin Wang unsigned int *npins) 22941d32cfcSBaolin Wang { 23041d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 23141d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 23241d32cfcSBaolin Wang 23341d32cfcSBaolin Wang if (selector >= info->ngroups) 23441d32cfcSBaolin Wang return -EINVAL; 23541d32cfcSBaolin Wang 23641d32cfcSBaolin Wang *pins = info->groups[selector].pins; 23741d32cfcSBaolin Wang *npins = info->groups[selector].npins; 23841d32cfcSBaolin Wang 23941d32cfcSBaolin Wang return 0; 24041d32cfcSBaolin Wang } 24141d32cfcSBaolin Wang 24241d32cfcSBaolin Wang static int sprd_dt_node_to_map(struct pinctrl_dev *pctldev, 24341d32cfcSBaolin Wang struct device_node *np, 24441d32cfcSBaolin Wang struct pinctrl_map **map, 24541d32cfcSBaolin Wang unsigned int *num_maps) 24641d32cfcSBaolin Wang { 24741d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 24841d32cfcSBaolin Wang const struct sprd_pin_group *grp; 24941d32cfcSBaolin Wang unsigned long *configs = NULL; 25041d32cfcSBaolin Wang unsigned int num_configs = 0; 25141d32cfcSBaolin Wang unsigned int reserved_maps = 0; 25241d32cfcSBaolin Wang unsigned int reserve = 0; 25341d32cfcSBaolin Wang const char *function; 25441d32cfcSBaolin Wang enum pinctrl_map_type type; 25541d32cfcSBaolin Wang int ret; 25641d32cfcSBaolin Wang 25741d32cfcSBaolin Wang grp = sprd_pinctrl_find_group_by_name(pctl, np->name); 25841d32cfcSBaolin Wang if (!grp) { 25941d32cfcSBaolin Wang dev_err(pctl->dev, "unable to find group for node %s\n", 26041d32cfcSBaolin Wang of_node_full_name(np)); 26141d32cfcSBaolin Wang return -EINVAL; 26241d32cfcSBaolin Wang } 26341d32cfcSBaolin Wang 26441d32cfcSBaolin Wang ret = of_property_count_strings(np, "pins"); 26541d32cfcSBaolin Wang if (ret < 0) 26641d32cfcSBaolin Wang return ret; 26741d32cfcSBaolin Wang 26841d32cfcSBaolin Wang if (ret == 1) 26941d32cfcSBaolin Wang type = PIN_MAP_TYPE_CONFIGS_PIN; 27041d32cfcSBaolin Wang else 27141d32cfcSBaolin Wang type = PIN_MAP_TYPE_CONFIGS_GROUP; 27241d32cfcSBaolin Wang 27341d32cfcSBaolin Wang ret = of_property_read_string(np, "function", &function); 27441d32cfcSBaolin Wang if (ret < 0) { 27541d32cfcSBaolin Wang if (ret != -EINVAL) 27641d32cfcSBaolin Wang dev_err(pctl->dev, 27741d32cfcSBaolin Wang "%s: could not parse property function\n", 27841d32cfcSBaolin Wang of_node_full_name(np)); 27941d32cfcSBaolin Wang function = NULL; 28041d32cfcSBaolin Wang } 28141d32cfcSBaolin Wang 28241d32cfcSBaolin Wang ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, 28341d32cfcSBaolin Wang &num_configs); 28441d32cfcSBaolin Wang if (ret < 0) { 28541d32cfcSBaolin Wang dev_err(pctl->dev, "%s: could not parse node property\n", 28641d32cfcSBaolin Wang of_node_full_name(np)); 28741d32cfcSBaolin Wang return ret; 28841d32cfcSBaolin Wang } 28941d32cfcSBaolin Wang 29041d32cfcSBaolin Wang *map = NULL; 29141d32cfcSBaolin Wang *num_maps = 0; 29241d32cfcSBaolin Wang 29341d32cfcSBaolin Wang if (function != NULL) 29441d32cfcSBaolin Wang reserve++; 29541d32cfcSBaolin Wang if (num_configs) 29641d32cfcSBaolin Wang reserve++; 29741d32cfcSBaolin Wang 29841d32cfcSBaolin Wang ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, 29941d32cfcSBaolin Wang num_maps, reserve); 30041d32cfcSBaolin Wang if (ret < 0) 30141d32cfcSBaolin Wang goto out; 30241d32cfcSBaolin Wang 30341d32cfcSBaolin Wang if (function) { 30441d32cfcSBaolin Wang ret = pinctrl_utils_add_map_mux(pctldev, map, 30541d32cfcSBaolin Wang &reserved_maps, num_maps, 30641d32cfcSBaolin Wang grp->name, function); 30741d32cfcSBaolin Wang if (ret < 0) 30841d32cfcSBaolin Wang goto out; 30941d32cfcSBaolin Wang } 31041d32cfcSBaolin Wang 31141d32cfcSBaolin Wang if (num_configs) { 31241d32cfcSBaolin Wang const char *group_or_pin; 31341d32cfcSBaolin Wang unsigned int pin_id; 31441d32cfcSBaolin Wang 31541d32cfcSBaolin Wang if (type == PIN_MAP_TYPE_CONFIGS_PIN) { 31641d32cfcSBaolin Wang pin_id = grp->pins[0]; 31741d32cfcSBaolin Wang group_or_pin = pin_get_name(pctldev, pin_id); 31841d32cfcSBaolin Wang } else { 31941d32cfcSBaolin Wang group_or_pin = grp->name; 32041d32cfcSBaolin Wang } 32141d32cfcSBaolin Wang 32241d32cfcSBaolin Wang ret = pinctrl_utils_add_map_configs(pctldev, map, 32341d32cfcSBaolin Wang &reserved_maps, num_maps, 32441d32cfcSBaolin Wang group_or_pin, configs, 32541d32cfcSBaolin Wang num_configs, type); 32641d32cfcSBaolin Wang } 32741d32cfcSBaolin Wang 32841d32cfcSBaolin Wang out: 32941d32cfcSBaolin Wang kfree(configs); 33041d32cfcSBaolin Wang return ret; 33141d32cfcSBaolin Wang } 33241d32cfcSBaolin Wang 33341d32cfcSBaolin Wang static void sprd_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 33441d32cfcSBaolin Wang unsigned int offset) 33541d32cfcSBaolin Wang { 33641d32cfcSBaolin Wang seq_printf(s, "%s", dev_name(pctldev->dev)); 33741d32cfcSBaolin Wang } 33841d32cfcSBaolin Wang 33941d32cfcSBaolin Wang static const struct pinctrl_ops sprd_pctrl_ops = { 34041d32cfcSBaolin Wang .get_groups_count = sprd_pctrl_group_count, 34141d32cfcSBaolin Wang .get_group_name = sprd_pctrl_group_name, 34241d32cfcSBaolin Wang .get_group_pins = sprd_pctrl_group_pins, 34341d32cfcSBaolin Wang .pin_dbg_show = sprd_pctrl_dbg_show, 34441d32cfcSBaolin Wang .dt_node_to_map = sprd_dt_node_to_map, 34541d32cfcSBaolin Wang .dt_free_map = pinctrl_utils_free_map, 34641d32cfcSBaolin Wang }; 34741d32cfcSBaolin Wang 348045b5792SColin Ian King static int sprd_pmx_get_function_count(struct pinctrl_dev *pctldev) 34941d32cfcSBaolin Wang { 35041d32cfcSBaolin Wang return PIN_FUNC_MAX; 35141d32cfcSBaolin Wang } 35241d32cfcSBaolin Wang 353045b5792SColin Ian King static const char *sprd_pmx_get_function_name(struct pinctrl_dev *pctldev, 35441d32cfcSBaolin Wang unsigned int selector) 35541d32cfcSBaolin Wang { 35641d32cfcSBaolin Wang switch (selector) { 35741d32cfcSBaolin Wang case PIN_FUNC_1: 35841d32cfcSBaolin Wang return "func1"; 35941d32cfcSBaolin Wang case PIN_FUNC_2: 36041d32cfcSBaolin Wang return "func2"; 36141d32cfcSBaolin Wang case PIN_FUNC_3: 36241d32cfcSBaolin Wang return "func3"; 36341d32cfcSBaolin Wang case PIN_FUNC_4: 36441d32cfcSBaolin Wang return "func4"; 36541d32cfcSBaolin Wang default: 36641d32cfcSBaolin Wang return "null"; 36741d32cfcSBaolin Wang } 36841d32cfcSBaolin Wang } 36941d32cfcSBaolin Wang 370045b5792SColin Ian King static int sprd_pmx_get_function_groups(struct pinctrl_dev *pctldev, 37141d32cfcSBaolin Wang unsigned int selector, 37241d32cfcSBaolin Wang const char * const **groups, 37341d32cfcSBaolin Wang unsigned int * const num_groups) 37441d32cfcSBaolin Wang { 37541d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 37641d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 37741d32cfcSBaolin Wang 37841d32cfcSBaolin Wang *groups = info->grp_names; 37941d32cfcSBaolin Wang *num_groups = info->ngroups; 38041d32cfcSBaolin Wang 38141d32cfcSBaolin Wang return 0; 38241d32cfcSBaolin Wang } 38341d32cfcSBaolin Wang 38441d32cfcSBaolin Wang static int sprd_pmx_set_mux(struct pinctrl_dev *pctldev, 38541d32cfcSBaolin Wang unsigned int func_selector, 38641d32cfcSBaolin Wang unsigned int group_selector) 38741d32cfcSBaolin Wang { 38841d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 38941d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 39041d32cfcSBaolin Wang struct sprd_pin_group *grp = &info->groups[group_selector]; 39141d32cfcSBaolin Wang unsigned int i, grp_pins = grp->npins; 39241d32cfcSBaolin Wang unsigned long reg; 39341d32cfcSBaolin Wang unsigned int val = 0; 39441d32cfcSBaolin Wang 3954ce504c4SDan Carpenter if (group_selector >= info->ngroups) 39641d32cfcSBaolin Wang return -EINVAL; 39741d32cfcSBaolin Wang 39841d32cfcSBaolin Wang switch (func_selector) { 39941d32cfcSBaolin Wang case PIN_FUNC_1: 40041d32cfcSBaolin Wang val &= PIN_FUNC_SEL_1; 40141d32cfcSBaolin Wang break; 40241d32cfcSBaolin Wang case PIN_FUNC_2: 40341d32cfcSBaolin Wang val |= PIN_FUNC_SEL_2; 40441d32cfcSBaolin Wang break; 40541d32cfcSBaolin Wang case PIN_FUNC_3: 40641d32cfcSBaolin Wang val |= PIN_FUNC_SEL_3; 40741d32cfcSBaolin Wang break; 40841d32cfcSBaolin Wang case PIN_FUNC_4: 40941d32cfcSBaolin Wang val |= PIN_FUNC_SEL_4; 41041d32cfcSBaolin Wang break; 41141d32cfcSBaolin Wang default: 41241d32cfcSBaolin Wang break; 41341d32cfcSBaolin Wang } 41441d32cfcSBaolin Wang 41541d32cfcSBaolin Wang for (i = 0; i < grp_pins; i++) { 41641d32cfcSBaolin Wang unsigned int pin_id = grp->pins[i]; 41741d32cfcSBaolin Wang struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 41841d32cfcSBaolin Wang 41941d32cfcSBaolin Wang if (!pin || pin->type != COMMON_PIN) 42041d32cfcSBaolin Wang continue; 42141d32cfcSBaolin Wang 42241d32cfcSBaolin Wang reg = readl((void __iomem *)pin->reg); 42341d32cfcSBaolin Wang reg &= ~PIN_FUNC_MASK; 42441d32cfcSBaolin Wang reg |= val; 42541d32cfcSBaolin Wang writel(reg, (void __iomem *)pin->reg); 42641d32cfcSBaolin Wang } 42741d32cfcSBaolin Wang 42841d32cfcSBaolin Wang return 0; 42941d32cfcSBaolin Wang } 43041d32cfcSBaolin Wang 43141d32cfcSBaolin Wang static const struct pinmux_ops sprd_pmx_ops = { 43241d32cfcSBaolin Wang .get_functions_count = sprd_pmx_get_function_count, 43341d32cfcSBaolin Wang .get_function_name = sprd_pmx_get_function_name, 43441d32cfcSBaolin Wang .get_function_groups = sprd_pmx_get_function_groups, 43541d32cfcSBaolin Wang .set_mux = sprd_pmx_set_mux, 43641d32cfcSBaolin Wang }; 43741d32cfcSBaolin Wang 43841d32cfcSBaolin Wang static int sprd_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin_id, 43941d32cfcSBaolin Wang unsigned long *config) 44041d32cfcSBaolin Wang { 44141d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 44241d32cfcSBaolin Wang struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 44341d32cfcSBaolin Wang unsigned int param = pinconf_to_config_param(*config); 44441d32cfcSBaolin Wang unsigned int reg, arg; 44541d32cfcSBaolin Wang 44641d32cfcSBaolin Wang if (!pin) 44741d32cfcSBaolin Wang return -EINVAL; 44841d32cfcSBaolin Wang 44941d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN) { 45041d32cfcSBaolin Wang reg = (readl((void __iomem *)pin->reg) >> 45141d32cfcSBaolin Wang pin->bit_offset) & PINCTRL_BIT_MASK(pin->bit_width); 45241d32cfcSBaolin Wang } else { 45341d32cfcSBaolin Wang reg = readl((void __iomem *)pin->reg); 45441d32cfcSBaolin Wang } 45541d32cfcSBaolin Wang 45641d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN && 45741d32cfcSBaolin Wang param == SPRD_PIN_CONFIG_CONTROL) { 45841d32cfcSBaolin Wang arg = reg; 4592f22e202SBaolin Wang } else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) { 46041d32cfcSBaolin Wang switch (param) { 46141d32cfcSBaolin Wang case SPRD_PIN_CONFIG_SLEEP_MODE: 46241d32cfcSBaolin Wang arg = (reg >> SLEEP_MODE_SHIFT) & SLEEP_MODE_MASK; 46341d32cfcSBaolin Wang break; 46441d32cfcSBaolin Wang case PIN_CONFIG_INPUT_ENABLE: 46541d32cfcSBaolin Wang arg = (reg >> SLEEP_INPUT_SHIFT) & SLEEP_INPUT_MASK; 46641d32cfcSBaolin Wang break; 46741d32cfcSBaolin Wang case PIN_CONFIG_OUTPUT: 46841d32cfcSBaolin Wang arg = reg & SLEEP_OUTPUT_MASK; 46941d32cfcSBaolin Wang break; 47041d32cfcSBaolin Wang case PIN_CONFIG_DRIVE_STRENGTH: 47141d32cfcSBaolin Wang arg = (reg >> DRIVE_STRENGTH_SHIFT) & 47241d32cfcSBaolin Wang DRIVE_STRENGTH_MASK; 47341d32cfcSBaolin Wang break; 47441d32cfcSBaolin Wang case PIN_CONFIG_BIAS_PULL_DOWN: 47541d32cfcSBaolin Wang /* combine sleep pull down and pull down config */ 47641d32cfcSBaolin Wang arg = ((reg >> SLEEP_PULL_DOWN_SHIFT) & 47741d32cfcSBaolin Wang SLEEP_PULL_DOWN_MASK) << 16; 47841d32cfcSBaolin Wang arg |= (reg >> PULL_DOWN_SHIFT) & PULL_DOWN_MASK; 47941d32cfcSBaolin Wang break; 48041d32cfcSBaolin Wang case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 48141d32cfcSBaolin Wang arg = (reg >> INPUT_SCHMITT_SHIFT) & INPUT_SCHMITT_MASK; 48241d32cfcSBaolin Wang break; 48341d32cfcSBaolin Wang case PIN_CONFIG_BIAS_PULL_UP: 48441d32cfcSBaolin Wang /* combine sleep pull up and pull up config */ 48541d32cfcSBaolin Wang arg = ((reg >> SLEEP_PULL_UP_SHIFT) & 48641d32cfcSBaolin Wang SLEEP_PULL_UP_MASK) << 16; 48741d32cfcSBaolin Wang arg |= (reg >> PULL_UP_SHIFT) & PULL_UP_MASK; 48841d32cfcSBaolin Wang break; 489f8b05fe4SBaolin Wang case PIN_CONFIG_BIAS_DISABLE: 490f8b05fe4SBaolin Wang if ((reg & (SLEEP_PULL_DOWN | SLEEP_PULL_UP)) || 491f8b05fe4SBaolin Wang (reg & (PULL_DOWN | PULL_UP_4_7K | PULL_UP_20K))) 492f8b05fe4SBaolin Wang return -EINVAL; 493f8b05fe4SBaolin Wang 494f8b05fe4SBaolin Wang arg = 1; 495f8b05fe4SBaolin Wang break; 49641d32cfcSBaolin Wang case PIN_CONFIG_SLEEP_HARDWARE_STATE: 49741d32cfcSBaolin Wang arg = 0; 49841d32cfcSBaolin Wang break; 49941d32cfcSBaolin Wang default: 50041d32cfcSBaolin Wang return -ENOTSUPP; 50141d32cfcSBaolin Wang } 50241d32cfcSBaolin Wang } else { 50341d32cfcSBaolin Wang return -ENOTSUPP; 50441d32cfcSBaolin Wang } 50541d32cfcSBaolin Wang 50641d32cfcSBaolin Wang *config = pinconf_to_config_packed(param, arg); 50741d32cfcSBaolin Wang return 0; 50841d32cfcSBaolin Wang } 50941d32cfcSBaolin Wang 51041d32cfcSBaolin Wang static unsigned int sprd_pinconf_drive(unsigned int mA) 51141d32cfcSBaolin Wang { 51241d32cfcSBaolin Wang unsigned int val = 0; 51341d32cfcSBaolin Wang 51441d32cfcSBaolin Wang switch (mA) { 51541d32cfcSBaolin Wang case 2: 51641d32cfcSBaolin Wang break; 51741d32cfcSBaolin Wang case 4: 51841d32cfcSBaolin Wang val |= BIT(19); 51941d32cfcSBaolin Wang break; 52041d32cfcSBaolin Wang case 6: 52141d32cfcSBaolin Wang val |= BIT(20); 52241d32cfcSBaolin Wang break; 52341d32cfcSBaolin Wang case 8: 52441d32cfcSBaolin Wang val |= BIT(19) | BIT(20); 52541d32cfcSBaolin Wang break; 52641d32cfcSBaolin Wang case 10: 52741d32cfcSBaolin Wang val |= BIT(21); 52841d32cfcSBaolin Wang break; 52941d32cfcSBaolin Wang case 12: 53041d32cfcSBaolin Wang val |= BIT(21) | BIT(19); 53141d32cfcSBaolin Wang break; 53241d32cfcSBaolin Wang case 14: 53341d32cfcSBaolin Wang val |= BIT(21) | BIT(20); 53441d32cfcSBaolin Wang break; 53541d32cfcSBaolin Wang case 16: 53641d32cfcSBaolin Wang val |= BIT(19) | BIT(20) | BIT(21); 53741d32cfcSBaolin Wang break; 53841d32cfcSBaolin Wang case 20: 53941d32cfcSBaolin Wang val |= BIT(22); 54041d32cfcSBaolin Wang break; 54141d32cfcSBaolin Wang case 21: 54241d32cfcSBaolin Wang val |= BIT(22) | BIT(19); 54341d32cfcSBaolin Wang break; 54441d32cfcSBaolin Wang case 24: 54541d32cfcSBaolin Wang val |= BIT(22) | BIT(20); 54641d32cfcSBaolin Wang break; 54741d32cfcSBaolin Wang case 25: 54841d32cfcSBaolin Wang val |= BIT(22) | BIT(20) | BIT(19); 54941d32cfcSBaolin Wang break; 55041d32cfcSBaolin Wang case 27: 55141d32cfcSBaolin Wang val |= BIT(22) | BIT(21); 55241d32cfcSBaolin Wang break; 55341d32cfcSBaolin Wang case 29: 55441d32cfcSBaolin Wang val |= BIT(22) | BIT(21) | BIT(19); 55541d32cfcSBaolin Wang break; 55641d32cfcSBaolin Wang case 31: 55741d32cfcSBaolin Wang val |= BIT(22) | BIT(21) | BIT(20); 55841d32cfcSBaolin Wang break; 55941d32cfcSBaolin Wang case 33: 56041d32cfcSBaolin Wang val |= BIT(22) | BIT(21) | BIT(20) | BIT(19); 56141d32cfcSBaolin Wang break; 56241d32cfcSBaolin Wang default: 56341d32cfcSBaolin Wang break; 56441d32cfcSBaolin Wang } 56541d32cfcSBaolin Wang 56641d32cfcSBaolin Wang return val; 56741d32cfcSBaolin Wang } 56841d32cfcSBaolin Wang 56941d32cfcSBaolin Wang static bool sprd_pinctrl_check_sleep_config(unsigned long *configs, 57041d32cfcSBaolin Wang unsigned int num_configs) 57141d32cfcSBaolin Wang { 57241d32cfcSBaolin Wang unsigned int param; 57341d32cfcSBaolin Wang int i; 57441d32cfcSBaolin Wang 57541d32cfcSBaolin Wang for (i = 0; i < num_configs; i++) { 57641d32cfcSBaolin Wang param = pinconf_to_config_param(configs[i]); 57741d32cfcSBaolin Wang if (param == PIN_CONFIG_SLEEP_HARDWARE_STATE) 57841d32cfcSBaolin Wang return true; 57941d32cfcSBaolin Wang } 58041d32cfcSBaolin Wang 58141d32cfcSBaolin Wang return false; 58241d32cfcSBaolin Wang } 58341d32cfcSBaolin Wang 58441d32cfcSBaolin Wang static int sprd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id, 58541d32cfcSBaolin Wang unsigned long *configs, unsigned int num_configs) 58641d32cfcSBaolin Wang { 58741d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 58841d32cfcSBaolin Wang struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 58941d32cfcSBaolin Wang bool is_sleep_config; 59041d32cfcSBaolin Wang unsigned long reg; 59141d32cfcSBaolin Wang int i; 59241d32cfcSBaolin Wang 59341d32cfcSBaolin Wang if (!pin) 59441d32cfcSBaolin Wang return -EINVAL; 59541d32cfcSBaolin Wang 59641d32cfcSBaolin Wang is_sleep_config = sprd_pinctrl_check_sleep_config(configs, num_configs); 59741d32cfcSBaolin Wang 59841d32cfcSBaolin Wang for (i = 0; i < num_configs; i++) { 59941d32cfcSBaolin Wang unsigned int param, arg, shift, mask, val; 60041d32cfcSBaolin Wang 60141d32cfcSBaolin Wang param = pinconf_to_config_param(configs[i]); 60241d32cfcSBaolin Wang arg = pinconf_to_config_argument(configs[i]); 60341d32cfcSBaolin Wang 60441d32cfcSBaolin Wang val = 0; 60541d32cfcSBaolin Wang shift = 0; 60641d32cfcSBaolin Wang mask = 0; 60741d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN && 60841d32cfcSBaolin Wang param == SPRD_PIN_CONFIG_CONTROL) { 60941d32cfcSBaolin Wang val = arg; 6102f22e202SBaolin Wang } else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) { 61141d32cfcSBaolin Wang switch (param) { 61241d32cfcSBaolin Wang case SPRD_PIN_CONFIG_SLEEP_MODE: 61341d32cfcSBaolin Wang if (arg & AP_SLEEP) 61441d32cfcSBaolin Wang val |= AP_SLEEP_MODE; 61541d32cfcSBaolin Wang if (arg & PUBCP_SLEEP) 61641d32cfcSBaolin Wang val |= PUBCP_SLEEP_MODE; 61741d32cfcSBaolin Wang if (arg & TGLDSP_SLEEP) 61841d32cfcSBaolin Wang val |= TGLDSP_SLEEP_MODE; 61941d32cfcSBaolin Wang if (arg & AGDSP_SLEEP) 62041d32cfcSBaolin Wang val |= AGDSP_SLEEP_MODE; 621*e543b3f5SBruce Chen if (arg & CM4_SLEEP) 622*e543b3f5SBruce Chen val |= CM4_SLEEP_MODE; 62341d32cfcSBaolin Wang 62441d32cfcSBaolin Wang mask = SLEEP_MODE_MASK; 62541d32cfcSBaolin Wang shift = SLEEP_MODE_SHIFT; 62641d32cfcSBaolin Wang break; 62741d32cfcSBaolin Wang case PIN_CONFIG_INPUT_ENABLE: 62841d32cfcSBaolin Wang if (is_sleep_config == true) { 62941d32cfcSBaolin Wang if (arg > 0) 63041d32cfcSBaolin Wang val |= SLEEP_INPUT; 63141d32cfcSBaolin Wang else 63241d32cfcSBaolin Wang val &= ~SLEEP_INPUT; 63341d32cfcSBaolin Wang 63441d32cfcSBaolin Wang mask = SLEEP_INPUT_MASK; 63541d32cfcSBaolin Wang shift = SLEEP_INPUT_SHIFT; 63641d32cfcSBaolin Wang } 63741d32cfcSBaolin Wang break; 63841d32cfcSBaolin Wang case PIN_CONFIG_OUTPUT: 63941d32cfcSBaolin Wang if (is_sleep_config == true) { 64041d32cfcSBaolin Wang val |= SLEEP_OUTPUT; 64141d32cfcSBaolin Wang mask = SLEEP_OUTPUT_MASK; 64241d32cfcSBaolin Wang shift = SLEEP_OUTPUT_SHIFT; 64341d32cfcSBaolin Wang } 64441d32cfcSBaolin Wang break; 64541d32cfcSBaolin Wang case PIN_CONFIG_DRIVE_STRENGTH: 64641d32cfcSBaolin Wang if (arg < 2 || arg > 60) 64741d32cfcSBaolin Wang return -EINVAL; 64841d32cfcSBaolin Wang 64941d32cfcSBaolin Wang val = sprd_pinconf_drive(arg); 65041d32cfcSBaolin Wang mask = DRIVE_STRENGTH_MASK; 65141d32cfcSBaolin Wang shift = DRIVE_STRENGTH_SHIFT; 65241d32cfcSBaolin Wang break; 65341d32cfcSBaolin Wang case PIN_CONFIG_BIAS_PULL_DOWN: 65441d32cfcSBaolin Wang if (is_sleep_config == true) { 65541d32cfcSBaolin Wang val |= SLEEP_PULL_DOWN; 65641d32cfcSBaolin Wang mask = SLEEP_PULL_DOWN_MASK; 65741d32cfcSBaolin Wang shift = SLEEP_PULL_DOWN_SHIFT; 65841d32cfcSBaolin Wang } else { 65941d32cfcSBaolin Wang val |= PULL_DOWN; 66041d32cfcSBaolin Wang mask = PULL_DOWN_MASK; 66141d32cfcSBaolin Wang shift = PULL_DOWN_SHIFT; 66241d32cfcSBaolin Wang } 66341d32cfcSBaolin Wang break; 66441d32cfcSBaolin Wang case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 66541d32cfcSBaolin Wang if (arg > 0) 66641d32cfcSBaolin Wang val |= INPUT_SCHMITT; 66741d32cfcSBaolin Wang else 66841d32cfcSBaolin Wang val &= ~INPUT_SCHMITT; 66941d32cfcSBaolin Wang 67041d32cfcSBaolin Wang mask = INPUT_SCHMITT_MASK; 67141d32cfcSBaolin Wang shift = INPUT_SCHMITT_SHIFT; 67241d32cfcSBaolin Wang break; 67341d32cfcSBaolin Wang case PIN_CONFIG_BIAS_PULL_UP: 67441d32cfcSBaolin Wang if (is_sleep_config == true) { 67541d32cfcSBaolin Wang val |= SLEEP_PULL_UP; 67641d32cfcSBaolin Wang mask = SLEEP_PULL_UP_MASK; 67741d32cfcSBaolin Wang shift = SLEEP_PULL_UP_SHIFT; 67841d32cfcSBaolin Wang } else { 67941d32cfcSBaolin Wang if (arg == 20000) 68041d32cfcSBaolin Wang val |= PULL_UP_20K; 68141d32cfcSBaolin Wang else if (arg == 4700) 68241d32cfcSBaolin Wang val |= PULL_UP_4_7K; 68341d32cfcSBaolin Wang 68441d32cfcSBaolin Wang mask = PULL_UP_MASK; 68541d32cfcSBaolin Wang shift = PULL_UP_SHIFT; 68641d32cfcSBaolin Wang } 68741d32cfcSBaolin Wang break; 688f8b05fe4SBaolin Wang case PIN_CONFIG_BIAS_DISABLE: 689f8b05fe4SBaolin Wang if (is_sleep_config == true) { 690f8b05fe4SBaolin Wang val = shift = 0; 691f8b05fe4SBaolin Wang mask = SLEEP_PULL_DOWN | SLEEP_PULL_UP; 692f8b05fe4SBaolin Wang } else { 693f8b05fe4SBaolin Wang val = shift = 0; 694f8b05fe4SBaolin Wang mask = PULL_DOWN | PULL_UP_20K | 695f8b05fe4SBaolin Wang PULL_UP_4_7K; 696f8b05fe4SBaolin Wang } 697f8b05fe4SBaolin Wang break; 69841d32cfcSBaolin Wang case PIN_CONFIG_SLEEP_HARDWARE_STATE: 69941d32cfcSBaolin Wang continue; 70041d32cfcSBaolin Wang default: 70141d32cfcSBaolin Wang return -ENOTSUPP; 70241d32cfcSBaolin Wang } 70341d32cfcSBaolin Wang } else { 70441d32cfcSBaolin Wang return -ENOTSUPP; 70541d32cfcSBaolin Wang } 70641d32cfcSBaolin Wang 70741d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN) { 70841d32cfcSBaolin Wang reg = readl((void __iomem *)pin->reg); 70941d32cfcSBaolin Wang reg &= ~(PINCTRL_BIT_MASK(pin->bit_width) 71041d32cfcSBaolin Wang << pin->bit_offset); 71141d32cfcSBaolin Wang reg |= (val & PINCTRL_BIT_MASK(pin->bit_width)) 71241d32cfcSBaolin Wang << pin->bit_offset; 71341d32cfcSBaolin Wang writel(reg, (void __iomem *)pin->reg); 71441d32cfcSBaolin Wang } else { 71541d32cfcSBaolin Wang reg = readl((void __iomem *)pin->reg); 71641d32cfcSBaolin Wang reg &= ~(mask << shift); 71741d32cfcSBaolin Wang reg |= val; 71841d32cfcSBaolin Wang writel(reg, (void __iomem *)pin->reg); 71941d32cfcSBaolin Wang } 72041d32cfcSBaolin Wang } 72141d32cfcSBaolin Wang 72241d32cfcSBaolin Wang return 0; 72341d32cfcSBaolin Wang } 72441d32cfcSBaolin Wang 72541d32cfcSBaolin Wang static int sprd_pinconf_group_get(struct pinctrl_dev *pctldev, 72641d32cfcSBaolin Wang unsigned int selector, unsigned long *config) 72741d32cfcSBaolin Wang { 72841d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 72941d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 73041d32cfcSBaolin Wang struct sprd_pin_group *grp; 73141d32cfcSBaolin Wang unsigned int pin_id; 73241d32cfcSBaolin Wang 7334ce504c4SDan Carpenter if (selector >= info->ngroups) 73441d32cfcSBaolin Wang return -EINVAL; 73541d32cfcSBaolin Wang 73641d32cfcSBaolin Wang grp = &info->groups[selector]; 73741d32cfcSBaolin Wang pin_id = grp->pins[0]; 73841d32cfcSBaolin Wang 73941d32cfcSBaolin Wang return sprd_pinconf_get(pctldev, pin_id, config); 74041d32cfcSBaolin Wang } 74141d32cfcSBaolin Wang 74241d32cfcSBaolin Wang static int sprd_pinconf_group_set(struct pinctrl_dev *pctldev, 74341d32cfcSBaolin Wang unsigned int selector, 74441d32cfcSBaolin Wang unsigned long *configs, 74541d32cfcSBaolin Wang unsigned int num_configs) 74641d32cfcSBaolin Wang { 74741d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 74841d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 74941d32cfcSBaolin Wang struct sprd_pin_group *grp; 75041d32cfcSBaolin Wang int ret, i; 75141d32cfcSBaolin Wang 7524ce504c4SDan Carpenter if (selector >= info->ngroups) 75341d32cfcSBaolin Wang return -EINVAL; 75441d32cfcSBaolin Wang 75541d32cfcSBaolin Wang grp = &info->groups[selector]; 75641d32cfcSBaolin Wang 75741d32cfcSBaolin Wang for (i = 0; i < grp->npins; i++) { 75841d32cfcSBaolin Wang unsigned int pin_id = grp->pins[i]; 75941d32cfcSBaolin Wang 76041d32cfcSBaolin Wang ret = sprd_pinconf_set(pctldev, pin_id, configs, num_configs); 76141d32cfcSBaolin Wang if (ret) 76241d32cfcSBaolin Wang return ret; 76341d32cfcSBaolin Wang } 76441d32cfcSBaolin Wang 76541d32cfcSBaolin Wang return 0; 76641d32cfcSBaolin Wang } 76741d32cfcSBaolin Wang 76841d32cfcSBaolin Wang static int sprd_pinconf_get_config(struct pinctrl_dev *pctldev, 76941d32cfcSBaolin Wang unsigned int pin_id, 77041d32cfcSBaolin Wang unsigned long *config) 77141d32cfcSBaolin Wang { 77241d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 77341d32cfcSBaolin Wang struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 77441d32cfcSBaolin Wang 77541d32cfcSBaolin Wang if (!pin) 77641d32cfcSBaolin Wang return -EINVAL; 77741d32cfcSBaolin Wang 77841d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN) { 77941d32cfcSBaolin Wang *config = (readl((void __iomem *)pin->reg) >> 78041d32cfcSBaolin Wang pin->bit_offset) & PINCTRL_BIT_MASK(pin->bit_width); 78141d32cfcSBaolin Wang } else { 78241d32cfcSBaolin Wang *config = readl((void __iomem *)pin->reg); 78341d32cfcSBaolin Wang } 78441d32cfcSBaolin Wang 78541d32cfcSBaolin Wang return 0; 78641d32cfcSBaolin Wang } 78741d32cfcSBaolin Wang 78841d32cfcSBaolin Wang static void sprd_pinconf_dbg_show(struct pinctrl_dev *pctldev, 78941d32cfcSBaolin Wang struct seq_file *s, unsigned int pin_id) 79041d32cfcSBaolin Wang { 79141d32cfcSBaolin Wang unsigned long config; 79241d32cfcSBaolin Wang int ret; 79341d32cfcSBaolin Wang 79441d32cfcSBaolin Wang ret = sprd_pinconf_get_config(pctldev, pin_id, &config); 79541d32cfcSBaolin Wang if (ret) 79641d32cfcSBaolin Wang return; 79741d32cfcSBaolin Wang 79841d32cfcSBaolin Wang seq_printf(s, "0x%lx", config); 79941d32cfcSBaolin Wang } 80041d32cfcSBaolin Wang 80141d32cfcSBaolin Wang static void sprd_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, 80241d32cfcSBaolin Wang struct seq_file *s, 80341d32cfcSBaolin Wang unsigned int selector) 80441d32cfcSBaolin Wang { 80541d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 80641d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 80741d32cfcSBaolin Wang struct sprd_pin_group *grp; 80841d32cfcSBaolin Wang unsigned long config; 80941d32cfcSBaolin Wang const char *name; 81041d32cfcSBaolin Wang int i, ret; 81141d32cfcSBaolin Wang 8124ce504c4SDan Carpenter if (selector >= info->ngroups) 81341d32cfcSBaolin Wang return; 81441d32cfcSBaolin Wang 81541d32cfcSBaolin Wang grp = &info->groups[selector]; 81641d32cfcSBaolin Wang 8179d2fc7c3SMarkus Elfring seq_putc(s, '\n'); 81841d32cfcSBaolin Wang for (i = 0; i < grp->npins; i++, config++) { 81941d32cfcSBaolin Wang unsigned int pin_id = grp->pins[i]; 82041d32cfcSBaolin Wang 82141d32cfcSBaolin Wang name = pin_get_name(pctldev, pin_id); 82241d32cfcSBaolin Wang ret = sprd_pinconf_get_config(pctldev, pin_id, &config); 82341d32cfcSBaolin Wang if (ret) 82441d32cfcSBaolin Wang return; 82541d32cfcSBaolin Wang 82641d32cfcSBaolin Wang seq_printf(s, "%s: 0x%lx ", name, config); 82741d32cfcSBaolin Wang } 82841d32cfcSBaolin Wang } 82941d32cfcSBaolin Wang 83041d32cfcSBaolin Wang static const struct pinconf_ops sprd_pinconf_ops = { 83141d32cfcSBaolin Wang .is_generic = true, 83241d32cfcSBaolin Wang .pin_config_get = sprd_pinconf_get, 83341d32cfcSBaolin Wang .pin_config_set = sprd_pinconf_set, 83441d32cfcSBaolin Wang .pin_config_group_get = sprd_pinconf_group_get, 83541d32cfcSBaolin Wang .pin_config_group_set = sprd_pinconf_group_set, 83641d32cfcSBaolin Wang .pin_config_dbg_show = sprd_pinconf_dbg_show, 83741d32cfcSBaolin Wang .pin_config_group_dbg_show = sprd_pinconf_group_dbg_show, 83841d32cfcSBaolin Wang }; 83941d32cfcSBaolin Wang 84041d32cfcSBaolin Wang static const struct pinconf_generic_params sprd_dt_params[] = { 84141d32cfcSBaolin Wang {"sprd,control", SPRD_PIN_CONFIG_CONTROL, 0}, 84241d32cfcSBaolin Wang {"sprd,sleep-mode", SPRD_PIN_CONFIG_SLEEP_MODE, 0}, 84341d32cfcSBaolin Wang }; 84441d32cfcSBaolin Wang 84541d32cfcSBaolin Wang #ifdef CONFIG_DEBUG_FS 84641d32cfcSBaolin Wang static const struct pin_config_item sprd_conf_items[] = { 84741d32cfcSBaolin Wang PCONFDUMP(SPRD_PIN_CONFIG_CONTROL, "global control", NULL, true), 84841d32cfcSBaolin Wang PCONFDUMP(SPRD_PIN_CONFIG_SLEEP_MODE, "sleep mode", NULL, true), 84941d32cfcSBaolin Wang }; 85041d32cfcSBaolin Wang #endif 85141d32cfcSBaolin Wang 85241d32cfcSBaolin Wang static struct pinctrl_desc sprd_pinctrl_desc = { 85341d32cfcSBaolin Wang .pctlops = &sprd_pctrl_ops, 85441d32cfcSBaolin Wang .pmxops = &sprd_pmx_ops, 85541d32cfcSBaolin Wang .confops = &sprd_pinconf_ops, 85641d32cfcSBaolin Wang .num_custom_params = ARRAY_SIZE(sprd_dt_params), 85741d32cfcSBaolin Wang .custom_params = sprd_dt_params, 85841d32cfcSBaolin Wang #ifdef CONFIG_DEBUG_FS 85941d32cfcSBaolin Wang .custom_conf_items = sprd_conf_items, 86041d32cfcSBaolin Wang #endif 86141d32cfcSBaolin Wang .owner = THIS_MODULE, 86241d32cfcSBaolin Wang }; 86341d32cfcSBaolin Wang 86441d32cfcSBaolin Wang static int sprd_pinctrl_parse_groups(struct device_node *np, 86541d32cfcSBaolin Wang struct sprd_pinctrl *sprd_pctl, 86641d32cfcSBaolin Wang struct sprd_pin_group *grp) 86741d32cfcSBaolin Wang { 86841d32cfcSBaolin Wang struct property *prop; 86941d32cfcSBaolin Wang const char *pin_name; 87041d32cfcSBaolin Wang int ret, i = 0; 87141d32cfcSBaolin Wang 87241d32cfcSBaolin Wang ret = of_property_count_strings(np, "pins"); 87341d32cfcSBaolin Wang if (ret < 0) 87441d32cfcSBaolin Wang return ret; 87541d32cfcSBaolin Wang 87641d32cfcSBaolin Wang grp->name = np->name; 87741d32cfcSBaolin Wang grp->npins = ret; 878a86854d0SKees Cook grp->pins = devm_kcalloc(sprd_pctl->dev, 879a86854d0SKees Cook grp->npins, sizeof(unsigned int), 880a86854d0SKees Cook GFP_KERNEL); 88141d32cfcSBaolin Wang if (!grp->pins) 88241d32cfcSBaolin Wang return -ENOMEM; 88341d32cfcSBaolin Wang 88441d32cfcSBaolin Wang of_property_for_each_string(np, "pins", prop, pin_name) { 88541d32cfcSBaolin Wang ret = sprd_pinctrl_get_id_by_name(sprd_pctl, pin_name); 88641d32cfcSBaolin Wang if (ret >= 0) 88741d32cfcSBaolin Wang grp->pins[i++] = ret; 88841d32cfcSBaolin Wang } 88941d32cfcSBaolin Wang 89041d32cfcSBaolin Wang for (i = 0; i < grp->npins; i++) { 89141d32cfcSBaolin Wang dev_dbg(sprd_pctl->dev, 89241d32cfcSBaolin Wang "Group[%s] contains [%d] pins: id = %d\n", 89341d32cfcSBaolin Wang grp->name, grp->npins, grp->pins[i]); 89441d32cfcSBaolin Wang } 89541d32cfcSBaolin Wang 89641d32cfcSBaolin Wang return 0; 89741d32cfcSBaolin Wang } 89841d32cfcSBaolin Wang 89941d32cfcSBaolin Wang static unsigned int sprd_pinctrl_get_groups(struct device_node *np) 90041d32cfcSBaolin Wang { 90141d32cfcSBaolin Wang struct device_node *child; 90241d32cfcSBaolin Wang unsigned int group_cnt, cnt; 90341d32cfcSBaolin Wang 90441d32cfcSBaolin Wang group_cnt = of_get_child_count(np); 90541d32cfcSBaolin Wang 90641d32cfcSBaolin Wang for_each_child_of_node(np, child) { 90741d32cfcSBaolin Wang cnt = of_get_child_count(child); 90841d32cfcSBaolin Wang if (cnt > 0) 90941d32cfcSBaolin Wang group_cnt += cnt; 91041d32cfcSBaolin Wang } 91141d32cfcSBaolin Wang 91241d32cfcSBaolin Wang return group_cnt; 91341d32cfcSBaolin Wang } 91441d32cfcSBaolin Wang 91541d32cfcSBaolin Wang static int sprd_pinctrl_parse_dt(struct sprd_pinctrl *sprd_pctl) 91641d32cfcSBaolin Wang { 91741d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 91841d32cfcSBaolin Wang struct device_node *np = sprd_pctl->dev->of_node; 91941d32cfcSBaolin Wang struct device_node *child, *sub_child; 92041d32cfcSBaolin Wang struct sprd_pin_group *grp; 92141d32cfcSBaolin Wang const char **temp; 92241d32cfcSBaolin Wang int ret; 92341d32cfcSBaolin Wang 92441d32cfcSBaolin Wang if (!np) 92541d32cfcSBaolin Wang return -ENODEV; 92641d32cfcSBaolin Wang 92741d32cfcSBaolin Wang info->ngroups = sprd_pinctrl_get_groups(np); 92841d32cfcSBaolin Wang if (!info->ngroups) 92941d32cfcSBaolin Wang return 0; 93041d32cfcSBaolin Wang 931a86854d0SKees Cook info->groups = devm_kcalloc(sprd_pctl->dev, 932a86854d0SKees Cook info->ngroups, 93341d32cfcSBaolin Wang sizeof(struct sprd_pin_group), 93441d32cfcSBaolin Wang GFP_KERNEL); 93541d32cfcSBaolin Wang if (!info->groups) 93641d32cfcSBaolin Wang return -ENOMEM; 93741d32cfcSBaolin Wang 938a86854d0SKees Cook info->grp_names = devm_kcalloc(sprd_pctl->dev, 939a86854d0SKees Cook info->ngroups, sizeof(char *), 94041d32cfcSBaolin Wang GFP_KERNEL); 94141d32cfcSBaolin Wang if (!info->grp_names) 94241d32cfcSBaolin Wang return -ENOMEM; 94341d32cfcSBaolin Wang 94441d32cfcSBaolin Wang temp = info->grp_names; 94541d32cfcSBaolin Wang grp = info->groups; 94641d32cfcSBaolin Wang 94741d32cfcSBaolin Wang for_each_child_of_node(np, child) { 94841d32cfcSBaolin Wang ret = sprd_pinctrl_parse_groups(child, sprd_pctl, grp); 9495a6bc290SNishka Dasgupta if (ret) { 9505a6bc290SNishka Dasgupta of_node_put(child); 95141d32cfcSBaolin Wang return ret; 9525a6bc290SNishka Dasgupta } 95341d32cfcSBaolin Wang 95441d32cfcSBaolin Wang *temp++ = grp->name; 95541d32cfcSBaolin Wang grp++; 95641d32cfcSBaolin Wang 95741d32cfcSBaolin Wang if (of_get_child_count(child) > 0) { 95841d32cfcSBaolin Wang for_each_child_of_node(child, sub_child) { 95941d32cfcSBaolin Wang ret = sprd_pinctrl_parse_groups(sub_child, 96041d32cfcSBaolin Wang sprd_pctl, grp); 9615a6bc290SNishka Dasgupta if (ret) { 9625a6bc290SNishka Dasgupta of_node_put(sub_child); 9635a6bc290SNishka Dasgupta of_node_put(child); 96441d32cfcSBaolin Wang return ret; 9655a6bc290SNishka Dasgupta } 96641d32cfcSBaolin Wang 96741d32cfcSBaolin Wang *temp++ = grp->name; 96841d32cfcSBaolin Wang grp++; 96941d32cfcSBaolin Wang } 97041d32cfcSBaolin Wang } 97141d32cfcSBaolin Wang } 97241d32cfcSBaolin Wang 97341d32cfcSBaolin Wang return 0; 97441d32cfcSBaolin Wang } 97541d32cfcSBaolin Wang 97641d32cfcSBaolin Wang static int sprd_pinctrl_add_pins(struct sprd_pinctrl *sprd_pctl, 97741d32cfcSBaolin Wang struct sprd_pins_info *sprd_soc_pin_info, 97841d32cfcSBaolin Wang int pins_cnt) 97941d32cfcSBaolin Wang { 98041d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 98141d32cfcSBaolin Wang unsigned int ctrl_pin = 0, com_pin = 0; 98241d32cfcSBaolin Wang struct sprd_pin *pin; 98341d32cfcSBaolin Wang int i; 98441d32cfcSBaolin Wang 98541d32cfcSBaolin Wang info->npins = pins_cnt; 986a86854d0SKees Cook info->pins = devm_kcalloc(sprd_pctl->dev, 987a86854d0SKees Cook info->npins, sizeof(struct sprd_pin), 98841d32cfcSBaolin Wang GFP_KERNEL); 98941d32cfcSBaolin Wang if (!info->pins) 99041d32cfcSBaolin Wang return -ENOMEM; 99141d32cfcSBaolin Wang 99241d32cfcSBaolin Wang for (i = 0, pin = info->pins; i < info->npins; i++, pin++) { 99341d32cfcSBaolin Wang unsigned int reg; 99441d32cfcSBaolin Wang 99541d32cfcSBaolin Wang pin->name = sprd_soc_pin_info[i].name; 99641d32cfcSBaolin Wang pin->type = sprd_soc_pin_info[i].type; 99741d32cfcSBaolin Wang pin->number = sprd_soc_pin_info[i].num; 99841d32cfcSBaolin Wang reg = sprd_soc_pin_info[i].reg; 99941d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN) { 100041d32cfcSBaolin Wang pin->reg = (unsigned long)sprd_pctl->base + 100141d32cfcSBaolin Wang PINCTRL_REG_LEN * reg; 100241d32cfcSBaolin Wang pin->bit_offset = sprd_soc_pin_info[i].bit_offset; 100341d32cfcSBaolin Wang pin->bit_width = sprd_soc_pin_info[i].bit_width; 100441d32cfcSBaolin Wang ctrl_pin++; 100541d32cfcSBaolin Wang } else if (pin->type == COMMON_PIN) { 100641d32cfcSBaolin Wang pin->reg = (unsigned long)sprd_pctl->base + 100741d32cfcSBaolin Wang PINCTRL_REG_OFFSET + PINCTRL_REG_LEN * 100841d32cfcSBaolin Wang (i - ctrl_pin); 100941d32cfcSBaolin Wang com_pin++; 101041d32cfcSBaolin Wang } else if (pin->type == MISC_PIN) { 101141d32cfcSBaolin Wang pin->reg = (unsigned long)sprd_pctl->base + 101241d32cfcSBaolin Wang PINCTRL_REG_MISC_OFFSET + PINCTRL_REG_LEN * 101341d32cfcSBaolin Wang (i - ctrl_pin - com_pin); 101441d32cfcSBaolin Wang } 101541d32cfcSBaolin Wang } 101641d32cfcSBaolin Wang 101741d32cfcSBaolin Wang for (i = 0, pin = info->pins; i < info->npins; pin++, i++) { 101841d32cfcSBaolin Wang dev_dbg(sprd_pctl->dev, "pin name[%s-%d], type = %d, " 101941d32cfcSBaolin Wang "bit offset = %ld, bit width = %ld, reg = 0x%lx\n", 102041d32cfcSBaolin Wang pin->name, pin->number, pin->type, 102141d32cfcSBaolin Wang pin->bit_offset, pin->bit_width, pin->reg); 102241d32cfcSBaolin Wang } 102341d32cfcSBaolin Wang 102441d32cfcSBaolin Wang return 0; 102541d32cfcSBaolin Wang } 102641d32cfcSBaolin Wang 102741d32cfcSBaolin Wang int sprd_pinctrl_core_probe(struct platform_device *pdev, 102841d32cfcSBaolin Wang struct sprd_pins_info *sprd_soc_pin_info, 102941d32cfcSBaolin Wang int pins_cnt) 103041d32cfcSBaolin Wang { 103141d32cfcSBaolin Wang struct sprd_pinctrl *sprd_pctl; 103241d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *pinctrl_info; 103341d32cfcSBaolin Wang struct pinctrl_pin_desc *pin_desc; 103441d32cfcSBaolin Wang int ret, i; 103541d32cfcSBaolin Wang 103641d32cfcSBaolin Wang sprd_pctl = devm_kzalloc(&pdev->dev, sizeof(struct sprd_pinctrl), 103741d32cfcSBaolin Wang GFP_KERNEL); 103841d32cfcSBaolin Wang if (!sprd_pctl) 103941d32cfcSBaolin Wang return -ENOMEM; 104041d32cfcSBaolin Wang 1041e89febc7SBaolin Wang sprd_pctl->base = devm_platform_ioremap_resource(pdev, 0); 104241d32cfcSBaolin Wang if (IS_ERR(sprd_pctl->base)) 104341d32cfcSBaolin Wang return PTR_ERR(sprd_pctl->base); 104441d32cfcSBaolin Wang 104541d32cfcSBaolin Wang pinctrl_info = devm_kzalloc(&pdev->dev, 104641d32cfcSBaolin Wang sizeof(struct sprd_pinctrl_soc_info), 104741d32cfcSBaolin Wang GFP_KERNEL); 104841d32cfcSBaolin Wang if (!pinctrl_info) 104941d32cfcSBaolin Wang return -ENOMEM; 105041d32cfcSBaolin Wang 105141d32cfcSBaolin Wang sprd_pctl->info = pinctrl_info; 105241d32cfcSBaolin Wang sprd_pctl->dev = &pdev->dev; 105341d32cfcSBaolin Wang platform_set_drvdata(pdev, sprd_pctl); 105441d32cfcSBaolin Wang 105541d32cfcSBaolin Wang ret = sprd_pinctrl_add_pins(sprd_pctl, sprd_soc_pin_info, pins_cnt); 105641d32cfcSBaolin Wang if (ret) { 105741d32cfcSBaolin Wang dev_err(&pdev->dev, "fail to add pins information\n"); 105841d32cfcSBaolin Wang return ret; 105941d32cfcSBaolin Wang } 106041d32cfcSBaolin Wang 106163e037bcSBaolin Wang ret = sprd_pinctrl_parse_dt(sprd_pctl); 106263e037bcSBaolin Wang if (ret) { 106363e037bcSBaolin Wang dev_err(&pdev->dev, "fail to parse dt properties\n"); 106463e037bcSBaolin Wang return ret; 106563e037bcSBaolin Wang } 106663e037bcSBaolin Wang 1067a86854d0SKees Cook pin_desc = devm_kcalloc(&pdev->dev, 1068a86854d0SKees Cook pinctrl_info->npins, 106941d32cfcSBaolin Wang sizeof(struct pinctrl_pin_desc), 107041d32cfcSBaolin Wang GFP_KERNEL); 107141d32cfcSBaolin Wang if (!pin_desc) 107241d32cfcSBaolin Wang return -ENOMEM; 107341d32cfcSBaolin Wang 107441d32cfcSBaolin Wang for (i = 0; i < pinctrl_info->npins; i++) { 107541d32cfcSBaolin Wang pin_desc[i].number = pinctrl_info->pins[i].number; 107641d32cfcSBaolin Wang pin_desc[i].name = pinctrl_info->pins[i].name; 107741d32cfcSBaolin Wang pin_desc[i].drv_data = pinctrl_info; 107841d32cfcSBaolin Wang } 107941d32cfcSBaolin Wang 108041d32cfcSBaolin Wang sprd_pinctrl_desc.pins = pin_desc; 108141d32cfcSBaolin Wang sprd_pinctrl_desc.name = dev_name(&pdev->dev); 108241d32cfcSBaolin Wang sprd_pinctrl_desc.npins = pinctrl_info->npins; 108341d32cfcSBaolin Wang 108441d32cfcSBaolin Wang sprd_pctl->pctl = pinctrl_register(&sprd_pinctrl_desc, 108541d32cfcSBaolin Wang &pdev->dev, (void *)sprd_pctl); 108641d32cfcSBaolin Wang if (IS_ERR(sprd_pctl->pctl)) { 108741d32cfcSBaolin Wang dev_err(&pdev->dev, "could not register pinctrl driver\n"); 108841d32cfcSBaolin Wang return PTR_ERR(sprd_pctl->pctl); 108941d32cfcSBaolin Wang } 109041d32cfcSBaolin Wang 109141d32cfcSBaolin Wang return 0; 109241d32cfcSBaolin Wang } 109341d32cfcSBaolin Wang 109441d32cfcSBaolin Wang int sprd_pinctrl_remove(struct platform_device *pdev) 109541d32cfcSBaolin Wang { 109641d32cfcSBaolin Wang struct sprd_pinctrl *sprd_pctl = platform_get_drvdata(pdev); 109741d32cfcSBaolin Wang 109841d32cfcSBaolin Wang pinctrl_unregister(sprd_pctl->pctl); 109941d32cfcSBaolin Wang return 0; 110041d32cfcSBaolin Wang } 110141d32cfcSBaolin Wang 110241d32cfcSBaolin Wang void sprd_pinctrl_shutdown(struct platform_device *pdev) 110341d32cfcSBaolin Wang { 110441470c37SDan Carpenter struct pinctrl *pinctl; 110541d32cfcSBaolin Wang struct pinctrl_state *state; 110641d32cfcSBaolin Wang 110741470c37SDan Carpenter pinctl = devm_pinctrl_get(&pdev->dev); 110841470c37SDan Carpenter if (IS_ERR(pinctl)) 110941470c37SDan Carpenter return; 111041d32cfcSBaolin Wang state = pinctrl_lookup_state(pinctl, "shutdown"); 111141470c37SDan Carpenter if (IS_ERR(state)) 111241470c37SDan Carpenter return; 111341d32cfcSBaolin Wang pinctrl_select_state(pinctl, state); 111441d32cfcSBaolin Wang } 111541d32cfcSBaolin Wang 111641d32cfcSBaolin Wang MODULE_DESCRIPTION("SPREADTRUM Pin Controller Driver"); 111741d32cfcSBaolin Wang MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>"); 111841d32cfcSBaolin Wang MODULE_LICENSE("GPL v2"); 1119