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> 16*82a045abSAndy Shevchenko #include <linux/seq_file.h> 17*82a045abSAndy Shevchenko #include <linux/slab.h> 18*82a045abSAndy Shevchenko 19*82a045abSAndy Shevchenko #include <linux/pinctrl/consumer.h> 2041d32cfcSBaolin Wang #include <linux/pinctrl/machine.h> 2141d32cfcSBaolin Wang #include <linux/pinctrl/pinconf-generic.h> 22*82a045abSAndy Shevchenko #include <linux/pinctrl/pinconf.h> 2341d32cfcSBaolin Wang #include <linux/pinctrl/pinctrl.h> 2441d32cfcSBaolin Wang #include <linux/pinctrl/pinmux.h> 2541d32cfcSBaolin Wang 2641d32cfcSBaolin Wang #include "../core.h" 2741d32cfcSBaolin Wang #include "../pinmux.h" 2841d32cfcSBaolin Wang #include "../pinconf.h" 2941d32cfcSBaolin Wang #include "../pinctrl-utils.h" 3041d32cfcSBaolin Wang #include "pinctrl-sprd.h" 3141d32cfcSBaolin Wang 3241d32cfcSBaolin Wang #define PINCTRL_BIT_MASK(width) (~(~0UL << (width))) 3341d32cfcSBaolin Wang #define PINCTRL_REG_OFFSET 0x20 3441d32cfcSBaolin Wang #define PINCTRL_REG_MISC_OFFSET 0x4020 3541d32cfcSBaolin Wang #define PINCTRL_REG_LEN 0x4 3641d32cfcSBaolin Wang 3741d32cfcSBaolin Wang #define PIN_FUNC_MASK (BIT(4) | BIT(5)) 3841d32cfcSBaolin Wang #define PIN_FUNC_SEL_1 ~PIN_FUNC_MASK 3941d32cfcSBaolin Wang #define PIN_FUNC_SEL_2 BIT(4) 4041d32cfcSBaolin Wang #define PIN_FUNC_SEL_3 BIT(5) 4141d32cfcSBaolin Wang #define PIN_FUNC_SEL_4 PIN_FUNC_MASK 4241d32cfcSBaolin Wang 4341d32cfcSBaolin Wang #define AP_SLEEP_MODE BIT(13) 4441d32cfcSBaolin Wang #define PUBCP_SLEEP_MODE BIT(14) 4541d32cfcSBaolin Wang #define TGLDSP_SLEEP_MODE BIT(15) 4641d32cfcSBaolin Wang #define AGDSP_SLEEP_MODE BIT(16) 47e543b3f5SBruce Chen #define CM4_SLEEP_MODE BIT(17) 48e543b3f5SBruce Chen #define SLEEP_MODE_MASK GENMASK(5, 0) 4941d32cfcSBaolin Wang #define SLEEP_MODE_SHIFT 13 5041d32cfcSBaolin Wang 5141d32cfcSBaolin Wang #define SLEEP_INPUT BIT(1) 5241d32cfcSBaolin Wang #define SLEEP_INPUT_MASK 0x1 5341d32cfcSBaolin Wang #define SLEEP_INPUT_SHIFT 1 5441d32cfcSBaolin Wang 5541d32cfcSBaolin Wang #define SLEEP_OUTPUT BIT(0) 5641d32cfcSBaolin Wang #define SLEEP_OUTPUT_MASK 0x1 5741d32cfcSBaolin Wang #define SLEEP_OUTPUT_SHIFT 0 5841d32cfcSBaolin Wang 5941d32cfcSBaolin Wang #define DRIVE_STRENGTH_MASK GENMASK(3, 0) 6041d32cfcSBaolin Wang #define DRIVE_STRENGTH_SHIFT 19 6141d32cfcSBaolin Wang 6241d32cfcSBaolin Wang #define SLEEP_PULL_DOWN BIT(2) 6341d32cfcSBaolin Wang #define SLEEP_PULL_DOWN_MASK 0x1 6441d32cfcSBaolin Wang #define SLEEP_PULL_DOWN_SHIFT 2 6541d32cfcSBaolin Wang 6641d32cfcSBaolin Wang #define PULL_DOWN BIT(6) 6741d32cfcSBaolin Wang #define PULL_DOWN_MASK 0x1 6841d32cfcSBaolin Wang #define PULL_DOWN_SHIFT 6 6941d32cfcSBaolin Wang 7041d32cfcSBaolin Wang #define SLEEP_PULL_UP BIT(3) 7141d32cfcSBaolin Wang #define SLEEP_PULL_UP_MASK 0x1 7241d32cfcSBaolin Wang #define SLEEP_PULL_UP_SHIFT 3 7341d32cfcSBaolin Wang 7494873f6bSBaolin Wang #define PULL_UP_4_7K (BIT(12) | BIT(7)) 7594873f6bSBaolin Wang #define PULL_UP_20K BIT(7) 7641d32cfcSBaolin Wang #define PULL_UP_MASK 0x21 7741d32cfcSBaolin Wang #define PULL_UP_SHIFT 7 7841d32cfcSBaolin Wang 7941d32cfcSBaolin Wang #define INPUT_SCHMITT BIT(11) 8041d32cfcSBaolin Wang #define INPUT_SCHMITT_MASK 0x1 8141d32cfcSBaolin Wang #define INPUT_SCHMITT_SHIFT 11 8241d32cfcSBaolin Wang 8341d32cfcSBaolin Wang enum pin_sleep_mode { 8441d32cfcSBaolin Wang AP_SLEEP = BIT(0), 8541d32cfcSBaolin Wang PUBCP_SLEEP = BIT(1), 8641d32cfcSBaolin Wang TGLDSP_SLEEP = BIT(2), 8741d32cfcSBaolin Wang AGDSP_SLEEP = BIT(3), 88e543b3f5SBruce Chen CM4_SLEEP = BIT(4), 8941d32cfcSBaolin Wang }; 9041d32cfcSBaolin Wang 9141d32cfcSBaolin Wang enum pin_func_sel { 9241d32cfcSBaolin Wang PIN_FUNC_1, 9341d32cfcSBaolin Wang PIN_FUNC_2, 9441d32cfcSBaolin Wang PIN_FUNC_3, 9541d32cfcSBaolin Wang PIN_FUNC_4, 9641d32cfcSBaolin Wang PIN_FUNC_MAX, 9741d32cfcSBaolin Wang }; 9841d32cfcSBaolin Wang 9941d32cfcSBaolin Wang /** 10041d32cfcSBaolin Wang * struct sprd_pin: represent one pin's description 10141d32cfcSBaolin Wang * @name: pin name 10241d32cfcSBaolin Wang * @number: pin number 10341d32cfcSBaolin Wang * @type: pin type, can be GLOBAL_CTRL_PIN/COMMON_PIN/MISC_PIN 10441d32cfcSBaolin Wang * @reg: pin register address 10541d32cfcSBaolin Wang * @bit_offset: bit offset in pin register 10641d32cfcSBaolin Wang * @bit_width: bit width in pin register 10741d32cfcSBaolin Wang */ 10841d32cfcSBaolin Wang struct sprd_pin { 10941d32cfcSBaolin Wang const char *name; 11041d32cfcSBaolin Wang unsigned int number; 11141d32cfcSBaolin Wang enum pin_type type; 11241d32cfcSBaolin Wang unsigned long reg; 11341d32cfcSBaolin Wang unsigned long bit_offset; 11441d32cfcSBaolin Wang unsigned long bit_width; 11541d32cfcSBaolin Wang }; 11641d32cfcSBaolin Wang 11741d32cfcSBaolin Wang /** 11841d32cfcSBaolin Wang * struct sprd_pin_group: represent one group's description 11941d32cfcSBaolin Wang * @name: group name 12041d32cfcSBaolin Wang * @npins: pin numbers of this group 12141d32cfcSBaolin Wang * @pins: pointer to pins array 12241d32cfcSBaolin Wang */ 12341d32cfcSBaolin Wang struct sprd_pin_group { 12441d32cfcSBaolin Wang const char *name; 12541d32cfcSBaolin Wang unsigned int npins; 12641d32cfcSBaolin Wang unsigned int *pins; 12741d32cfcSBaolin Wang }; 12841d32cfcSBaolin Wang 12941d32cfcSBaolin Wang /** 13041d32cfcSBaolin Wang * struct sprd_pinctrl_soc_info: represent the SoC's pins description 13141d32cfcSBaolin Wang * @groups: pointer to groups of pins 13241d32cfcSBaolin Wang * @ngroups: group numbers of the whole SoC 13341d32cfcSBaolin Wang * @pins: pointer to pins description 13441d32cfcSBaolin Wang * @npins: pin numbers of the whole SoC 13541d32cfcSBaolin Wang * @grp_names: pointer to group names array 13641d32cfcSBaolin Wang */ 13741d32cfcSBaolin Wang struct sprd_pinctrl_soc_info { 13841d32cfcSBaolin Wang struct sprd_pin_group *groups; 13941d32cfcSBaolin Wang unsigned int ngroups; 14041d32cfcSBaolin Wang struct sprd_pin *pins; 14141d32cfcSBaolin Wang unsigned int npins; 14241d32cfcSBaolin Wang const char **grp_names; 14341d32cfcSBaolin Wang }; 14441d32cfcSBaolin Wang 14541d32cfcSBaolin Wang /** 14641d32cfcSBaolin Wang * struct sprd_pinctrl: represent the pin controller device 14741d32cfcSBaolin Wang * @dev: pointer to the device structure 14841d32cfcSBaolin Wang * @pctl: pointer to the pinctrl handle 14941d32cfcSBaolin Wang * @base: base address of the controller 15041d32cfcSBaolin Wang * @info: pointer to SoC's pins description information 15141d32cfcSBaolin Wang */ 15241d32cfcSBaolin Wang struct sprd_pinctrl { 15341d32cfcSBaolin Wang struct device *dev; 15441d32cfcSBaolin Wang struct pinctrl_dev *pctl; 15541d32cfcSBaolin Wang void __iomem *base; 15641d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info; 15741d32cfcSBaolin Wang }; 15841d32cfcSBaolin Wang 159957063c9SNathan Chancellor #define SPRD_PIN_CONFIG_CONTROL (PIN_CONFIG_END + 1) 160957063c9SNathan Chancellor #define SPRD_PIN_CONFIG_SLEEP_MODE (PIN_CONFIG_END + 2) 16141d32cfcSBaolin Wang 16241d32cfcSBaolin Wang static int sprd_pinctrl_get_id_by_name(struct sprd_pinctrl *sprd_pctl, 16341d32cfcSBaolin Wang const char *name) 16441d32cfcSBaolin Wang { 16541d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 16641d32cfcSBaolin Wang int i; 16741d32cfcSBaolin Wang 16841d32cfcSBaolin Wang for (i = 0; i < info->npins; i++) { 16941d32cfcSBaolin Wang if (!strcmp(info->pins[i].name, name)) 17041d32cfcSBaolin Wang return info->pins[i].number; 17141d32cfcSBaolin Wang } 17241d32cfcSBaolin Wang 17341d32cfcSBaolin Wang return -ENODEV; 17441d32cfcSBaolin Wang } 17541d32cfcSBaolin Wang 17641d32cfcSBaolin Wang static struct sprd_pin * 17741d32cfcSBaolin Wang sprd_pinctrl_get_pin_by_id(struct sprd_pinctrl *sprd_pctl, unsigned int id) 17841d32cfcSBaolin Wang { 17941d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 18041d32cfcSBaolin Wang struct sprd_pin *pin = NULL; 18141d32cfcSBaolin Wang int i; 18241d32cfcSBaolin Wang 18341d32cfcSBaolin Wang for (i = 0; i < info->npins; i++) { 18441d32cfcSBaolin Wang if (info->pins[i].number == id) { 18541d32cfcSBaolin Wang pin = &info->pins[i]; 18641d32cfcSBaolin Wang break; 18741d32cfcSBaolin Wang } 18841d32cfcSBaolin Wang } 18941d32cfcSBaolin Wang 19041d32cfcSBaolin Wang return pin; 19141d32cfcSBaolin Wang } 19241d32cfcSBaolin Wang 19341d32cfcSBaolin Wang static const struct sprd_pin_group * 19441d32cfcSBaolin Wang sprd_pinctrl_find_group_by_name(struct sprd_pinctrl *sprd_pctl, 19541d32cfcSBaolin Wang const char *name) 19641d32cfcSBaolin Wang { 19741d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 19841d32cfcSBaolin Wang const struct sprd_pin_group *grp = NULL; 19941d32cfcSBaolin Wang int i; 20041d32cfcSBaolin Wang 20141d32cfcSBaolin Wang for (i = 0; i < info->ngroups; i++) { 20241d32cfcSBaolin Wang if (!strcmp(info->groups[i].name, name)) { 20341d32cfcSBaolin Wang grp = &info->groups[i]; 20441d32cfcSBaolin Wang break; 20541d32cfcSBaolin Wang } 20641d32cfcSBaolin Wang } 20741d32cfcSBaolin Wang 20841d32cfcSBaolin Wang return grp; 20941d32cfcSBaolin Wang } 21041d32cfcSBaolin Wang 21141d32cfcSBaolin Wang static int sprd_pctrl_group_count(struct pinctrl_dev *pctldev) 21241d32cfcSBaolin Wang { 21341d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 21441d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 21541d32cfcSBaolin Wang 21641d32cfcSBaolin Wang return info->ngroups; 21741d32cfcSBaolin Wang } 21841d32cfcSBaolin Wang 21941d32cfcSBaolin Wang static const char *sprd_pctrl_group_name(struct pinctrl_dev *pctldev, 22041d32cfcSBaolin Wang unsigned int selector) 22141d32cfcSBaolin Wang { 22241d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 22341d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 22441d32cfcSBaolin Wang 22541d32cfcSBaolin Wang return info->groups[selector].name; 22641d32cfcSBaolin Wang } 22741d32cfcSBaolin Wang 22841d32cfcSBaolin Wang static int sprd_pctrl_group_pins(struct pinctrl_dev *pctldev, 22941d32cfcSBaolin Wang unsigned int selector, 23041d32cfcSBaolin Wang const unsigned int **pins, 23141d32cfcSBaolin Wang unsigned int *npins) 23241d32cfcSBaolin Wang { 23341d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 23441d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 23541d32cfcSBaolin Wang 23641d32cfcSBaolin Wang if (selector >= info->ngroups) 23741d32cfcSBaolin Wang return -EINVAL; 23841d32cfcSBaolin Wang 23941d32cfcSBaolin Wang *pins = info->groups[selector].pins; 24041d32cfcSBaolin Wang *npins = info->groups[selector].npins; 24141d32cfcSBaolin Wang 24241d32cfcSBaolin Wang return 0; 24341d32cfcSBaolin Wang } 24441d32cfcSBaolin Wang 24541d32cfcSBaolin Wang static int sprd_dt_node_to_map(struct pinctrl_dev *pctldev, 24641d32cfcSBaolin Wang struct device_node *np, 24741d32cfcSBaolin Wang struct pinctrl_map **map, 24841d32cfcSBaolin Wang unsigned int *num_maps) 24941d32cfcSBaolin Wang { 25041d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 25141d32cfcSBaolin Wang const struct sprd_pin_group *grp; 25241d32cfcSBaolin Wang unsigned long *configs = NULL; 25341d32cfcSBaolin Wang unsigned int num_configs = 0; 25441d32cfcSBaolin Wang unsigned int reserved_maps = 0; 25541d32cfcSBaolin Wang unsigned int reserve = 0; 25641d32cfcSBaolin Wang const char *function; 25741d32cfcSBaolin Wang enum pinctrl_map_type type; 25841d32cfcSBaolin Wang int ret; 25941d32cfcSBaolin Wang 26041d32cfcSBaolin Wang grp = sprd_pinctrl_find_group_by_name(pctl, np->name); 26141d32cfcSBaolin Wang if (!grp) { 26241d32cfcSBaolin Wang dev_err(pctl->dev, "unable to find group for node %s\n", 26341d32cfcSBaolin Wang of_node_full_name(np)); 26441d32cfcSBaolin Wang return -EINVAL; 26541d32cfcSBaolin Wang } 26641d32cfcSBaolin Wang 26741d32cfcSBaolin Wang ret = of_property_count_strings(np, "pins"); 26841d32cfcSBaolin Wang if (ret < 0) 26941d32cfcSBaolin Wang return ret; 27041d32cfcSBaolin Wang 27141d32cfcSBaolin Wang if (ret == 1) 27241d32cfcSBaolin Wang type = PIN_MAP_TYPE_CONFIGS_PIN; 27341d32cfcSBaolin Wang else 27441d32cfcSBaolin Wang type = PIN_MAP_TYPE_CONFIGS_GROUP; 27541d32cfcSBaolin Wang 27641d32cfcSBaolin Wang ret = of_property_read_string(np, "function", &function); 27741d32cfcSBaolin Wang if (ret < 0) { 27841d32cfcSBaolin Wang if (ret != -EINVAL) 27941d32cfcSBaolin Wang dev_err(pctl->dev, 28041d32cfcSBaolin Wang "%s: could not parse property function\n", 28141d32cfcSBaolin Wang of_node_full_name(np)); 28241d32cfcSBaolin Wang function = NULL; 28341d32cfcSBaolin Wang } 28441d32cfcSBaolin Wang 28541d32cfcSBaolin Wang ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, 28641d32cfcSBaolin Wang &num_configs); 28741d32cfcSBaolin Wang if (ret < 0) { 28841d32cfcSBaolin Wang dev_err(pctl->dev, "%s: could not parse node property\n", 28941d32cfcSBaolin Wang of_node_full_name(np)); 29041d32cfcSBaolin Wang return ret; 29141d32cfcSBaolin Wang } 29241d32cfcSBaolin Wang 29341d32cfcSBaolin Wang *map = NULL; 29441d32cfcSBaolin Wang *num_maps = 0; 29541d32cfcSBaolin Wang 29641d32cfcSBaolin Wang if (function != NULL) 29741d32cfcSBaolin Wang reserve++; 29841d32cfcSBaolin Wang if (num_configs) 29941d32cfcSBaolin Wang reserve++; 30041d32cfcSBaolin Wang 30141d32cfcSBaolin Wang ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, 30241d32cfcSBaolin Wang num_maps, reserve); 30341d32cfcSBaolin Wang if (ret < 0) 30441d32cfcSBaolin Wang goto out; 30541d32cfcSBaolin Wang 30641d32cfcSBaolin Wang if (function) { 30741d32cfcSBaolin Wang ret = pinctrl_utils_add_map_mux(pctldev, map, 30841d32cfcSBaolin Wang &reserved_maps, num_maps, 30941d32cfcSBaolin Wang grp->name, function); 31041d32cfcSBaolin Wang if (ret < 0) 31141d32cfcSBaolin Wang goto out; 31241d32cfcSBaolin Wang } 31341d32cfcSBaolin Wang 31441d32cfcSBaolin Wang if (num_configs) { 31541d32cfcSBaolin Wang const char *group_or_pin; 31641d32cfcSBaolin Wang unsigned int pin_id; 31741d32cfcSBaolin Wang 31841d32cfcSBaolin Wang if (type == PIN_MAP_TYPE_CONFIGS_PIN) { 31941d32cfcSBaolin Wang pin_id = grp->pins[0]; 32041d32cfcSBaolin Wang group_or_pin = pin_get_name(pctldev, pin_id); 32141d32cfcSBaolin Wang } else { 32241d32cfcSBaolin Wang group_or_pin = grp->name; 32341d32cfcSBaolin Wang } 32441d32cfcSBaolin Wang 32541d32cfcSBaolin Wang ret = pinctrl_utils_add_map_configs(pctldev, map, 32641d32cfcSBaolin Wang &reserved_maps, num_maps, 32741d32cfcSBaolin Wang group_or_pin, configs, 32841d32cfcSBaolin Wang num_configs, type); 32941d32cfcSBaolin Wang } 33041d32cfcSBaolin Wang 33141d32cfcSBaolin Wang out: 33241d32cfcSBaolin Wang kfree(configs); 33341d32cfcSBaolin Wang return ret; 33441d32cfcSBaolin Wang } 33541d32cfcSBaolin Wang 33641d32cfcSBaolin Wang static void sprd_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 33741d32cfcSBaolin Wang unsigned int offset) 33841d32cfcSBaolin Wang { 33941d32cfcSBaolin Wang seq_printf(s, "%s", dev_name(pctldev->dev)); 34041d32cfcSBaolin Wang } 34141d32cfcSBaolin Wang 34241d32cfcSBaolin Wang static const struct pinctrl_ops sprd_pctrl_ops = { 34341d32cfcSBaolin Wang .get_groups_count = sprd_pctrl_group_count, 34441d32cfcSBaolin Wang .get_group_name = sprd_pctrl_group_name, 34541d32cfcSBaolin Wang .get_group_pins = sprd_pctrl_group_pins, 34641d32cfcSBaolin Wang .pin_dbg_show = sprd_pctrl_dbg_show, 34741d32cfcSBaolin Wang .dt_node_to_map = sprd_dt_node_to_map, 34841d32cfcSBaolin Wang .dt_free_map = pinctrl_utils_free_map, 34941d32cfcSBaolin Wang }; 35041d32cfcSBaolin Wang 351045b5792SColin Ian King static int sprd_pmx_get_function_count(struct pinctrl_dev *pctldev) 35241d32cfcSBaolin Wang { 35341d32cfcSBaolin Wang return PIN_FUNC_MAX; 35441d32cfcSBaolin Wang } 35541d32cfcSBaolin Wang 356045b5792SColin Ian King static const char *sprd_pmx_get_function_name(struct pinctrl_dev *pctldev, 35741d32cfcSBaolin Wang unsigned int selector) 35841d32cfcSBaolin Wang { 35941d32cfcSBaolin Wang switch (selector) { 36041d32cfcSBaolin Wang case PIN_FUNC_1: 36141d32cfcSBaolin Wang return "func1"; 36241d32cfcSBaolin Wang case PIN_FUNC_2: 36341d32cfcSBaolin Wang return "func2"; 36441d32cfcSBaolin Wang case PIN_FUNC_3: 36541d32cfcSBaolin Wang return "func3"; 36641d32cfcSBaolin Wang case PIN_FUNC_4: 36741d32cfcSBaolin Wang return "func4"; 36841d32cfcSBaolin Wang default: 36941d32cfcSBaolin Wang return "null"; 37041d32cfcSBaolin Wang } 37141d32cfcSBaolin Wang } 37241d32cfcSBaolin Wang 373045b5792SColin Ian King static int sprd_pmx_get_function_groups(struct pinctrl_dev *pctldev, 37441d32cfcSBaolin Wang unsigned int selector, 37541d32cfcSBaolin Wang const char * const **groups, 37641d32cfcSBaolin Wang unsigned int * const num_groups) 37741d32cfcSBaolin Wang { 37841d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 37941d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 38041d32cfcSBaolin Wang 38141d32cfcSBaolin Wang *groups = info->grp_names; 38241d32cfcSBaolin Wang *num_groups = info->ngroups; 38341d32cfcSBaolin Wang 38441d32cfcSBaolin Wang return 0; 38541d32cfcSBaolin Wang } 38641d32cfcSBaolin Wang 38741d32cfcSBaolin Wang static int sprd_pmx_set_mux(struct pinctrl_dev *pctldev, 38841d32cfcSBaolin Wang unsigned int func_selector, 38941d32cfcSBaolin Wang unsigned int group_selector) 39041d32cfcSBaolin Wang { 39141d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 39241d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 39341d32cfcSBaolin Wang struct sprd_pin_group *grp = &info->groups[group_selector]; 39441d32cfcSBaolin Wang unsigned int i, grp_pins = grp->npins; 39541d32cfcSBaolin Wang unsigned long reg; 39641d32cfcSBaolin Wang unsigned int val = 0; 39741d32cfcSBaolin Wang 3984ce504c4SDan Carpenter if (group_selector >= info->ngroups) 39941d32cfcSBaolin Wang return -EINVAL; 40041d32cfcSBaolin Wang 40141d32cfcSBaolin Wang switch (func_selector) { 40241d32cfcSBaolin Wang case PIN_FUNC_1: 40341d32cfcSBaolin Wang val &= PIN_FUNC_SEL_1; 40441d32cfcSBaolin Wang break; 40541d32cfcSBaolin Wang case PIN_FUNC_2: 40641d32cfcSBaolin Wang val |= PIN_FUNC_SEL_2; 40741d32cfcSBaolin Wang break; 40841d32cfcSBaolin Wang case PIN_FUNC_3: 40941d32cfcSBaolin Wang val |= PIN_FUNC_SEL_3; 41041d32cfcSBaolin Wang break; 41141d32cfcSBaolin Wang case PIN_FUNC_4: 41241d32cfcSBaolin Wang val |= PIN_FUNC_SEL_4; 41341d32cfcSBaolin Wang break; 41441d32cfcSBaolin Wang default: 41541d32cfcSBaolin Wang break; 41641d32cfcSBaolin Wang } 41741d32cfcSBaolin Wang 41841d32cfcSBaolin Wang for (i = 0; i < grp_pins; i++) { 41941d32cfcSBaolin Wang unsigned int pin_id = grp->pins[i]; 42041d32cfcSBaolin Wang struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 42141d32cfcSBaolin Wang 42241d32cfcSBaolin Wang if (!pin || pin->type != COMMON_PIN) 42341d32cfcSBaolin Wang continue; 42441d32cfcSBaolin Wang 42541d32cfcSBaolin Wang reg = readl((void __iomem *)pin->reg); 42641d32cfcSBaolin Wang reg &= ~PIN_FUNC_MASK; 42741d32cfcSBaolin Wang reg |= val; 42841d32cfcSBaolin Wang writel(reg, (void __iomem *)pin->reg); 42941d32cfcSBaolin Wang } 43041d32cfcSBaolin Wang 43141d32cfcSBaolin Wang return 0; 43241d32cfcSBaolin Wang } 43341d32cfcSBaolin Wang 43441d32cfcSBaolin Wang static const struct pinmux_ops sprd_pmx_ops = { 43541d32cfcSBaolin Wang .get_functions_count = sprd_pmx_get_function_count, 43641d32cfcSBaolin Wang .get_function_name = sprd_pmx_get_function_name, 43741d32cfcSBaolin Wang .get_function_groups = sprd_pmx_get_function_groups, 43841d32cfcSBaolin Wang .set_mux = sprd_pmx_set_mux, 43941d32cfcSBaolin Wang }; 44041d32cfcSBaolin Wang 44141d32cfcSBaolin Wang static int sprd_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin_id, 44241d32cfcSBaolin Wang unsigned long *config) 44341d32cfcSBaolin Wang { 44441d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 44541d32cfcSBaolin Wang struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 44641d32cfcSBaolin Wang unsigned int param = pinconf_to_config_param(*config); 44741d32cfcSBaolin Wang unsigned int reg, arg; 44841d32cfcSBaolin Wang 44941d32cfcSBaolin Wang if (!pin) 45041d32cfcSBaolin Wang return -EINVAL; 45141d32cfcSBaolin Wang 45241d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN) { 45341d32cfcSBaolin Wang reg = (readl((void __iomem *)pin->reg) >> 45441d32cfcSBaolin Wang pin->bit_offset) & PINCTRL_BIT_MASK(pin->bit_width); 45541d32cfcSBaolin Wang } else { 45641d32cfcSBaolin Wang reg = readl((void __iomem *)pin->reg); 45741d32cfcSBaolin Wang } 45841d32cfcSBaolin Wang 45941d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN && 46041d32cfcSBaolin Wang param == SPRD_PIN_CONFIG_CONTROL) { 46141d32cfcSBaolin Wang arg = reg; 4622f22e202SBaolin Wang } else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) { 46341d32cfcSBaolin Wang switch (param) { 46441d32cfcSBaolin Wang case SPRD_PIN_CONFIG_SLEEP_MODE: 46541d32cfcSBaolin Wang arg = (reg >> SLEEP_MODE_SHIFT) & SLEEP_MODE_MASK; 46641d32cfcSBaolin Wang break; 46741d32cfcSBaolin Wang case PIN_CONFIG_INPUT_ENABLE: 46841d32cfcSBaolin Wang arg = (reg >> SLEEP_INPUT_SHIFT) & SLEEP_INPUT_MASK; 46941d32cfcSBaolin Wang break; 470bb0f472fSLinhua Xu case PIN_CONFIG_OUTPUT_ENABLE: 47141d32cfcSBaolin Wang arg = reg & SLEEP_OUTPUT_MASK; 47241d32cfcSBaolin Wang break; 4731592c4b9SLinhua Xu case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 4741592c4b9SLinhua Xu if ((reg & SLEEP_OUTPUT) || (reg & SLEEP_INPUT)) 4751592c4b9SLinhua Xu return -EINVAL; 4761592c4b9SLinhua Xu 4771592c4b9SLinhua Xu arg = 1; 4781592c4b9SLinhua Xu break; 47941d32cfcSBaolin Wang case PIN_CONFIG_DRIVE_STRENGTH: 48041d32cfcSBaolin Wang arg = (reg >> DRIVE_STRENGTH_SHIFT) & 48141d32cfcSBaolin Wang DRIVE_STRENGTH_MASK; 48241d32cfcSBaolin Wang break; 48341d32cfcSBaolin Wang case PIN_CONFIG_BIAS_PULL_DOWN: 48441d32cfcSBaolin Wang /* combine sleep pull down and pull down config */ 48541d32cfcSBaolin Wang arg = ((reg >> SLEEP_PULL_DOWN_SHIFT) & 48641d32cfcSBaolin Wang SLEEP_PULL_DOWN_MASK) << 16; 48741d32cfcSBaolin Wang arg |= (reg >> PULL_DOWN_SHIFT) & PULL_DOWN_MASK; 48841d32cfcSBaolin Wang break; 48941d32cfcSBaolin Wang case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 49041d32cfcSBaolin Wang arg = (reg >> INPUT_SCHMITT_SHIFT) & INPUT_SCHMITT_MASK; 49141d32cfcSBaolin Wang break; 49241d32cfcSBaolin Wang case PIN_CONFIG_BIAS_PULL_UP: 49341d32cfcSBaolin Wang /* combine sleep pull up and pull up config */ 49441d32cfcSBaolin Wang arg = ((reg >> SLEEP_PULL_UP_SHIFT) & 49541d32cfcSBaolin Wang SLEEP_PULL_UP_MASK) << 16; 49641d32cfcSBaolin Wang arg |= (reg >> PULL_UP_SHIFT) & PULL_UP_MASK; 49741d32cfcSBaolin Wang break; 498f8b05fe4SBaolin Wang case PIN_CONFIG_BIAS_DISABLE: 499f8b05fe4SBaolin Wang if ((reg & (SLEEP_PULL_DOWN | SLEEP_PULL_UP)) || 500f8b05fe4SBaolin Wang (reg & (PULL_DOWN | PULL_UP_4_7K | PULL_UP_20K))) 501f8b05fe4SBaolin Wang return -EINVAL; 502f8b05fe4SBaolin Wang 503f8b05fe4SBaolin Wang arg = 1; 504f8b05fe4SBaolin Wang break; 50541d32cfcSBaolin Wang case PIN_CONFIG_SLEEP_HARDWARE_STATE: 50641d32cfcSBaolin Wang arg = 0; 50741d32cfcSBaolin Wang break; 50841d32cfcSBaolin Wang default: 50941d32cfcSBaolin Wang return -ENOTSUPP; 51041d32cfcSBaolin Wang } 51141d32cfcSBaolin Wang } else { 51241d32cfcSBaolin Wang return -ENOTSUPP; 51341d32cfcSBaolin Wang } 51441d32cfcSBaolin Wang 51541d32cfcSBaolin Wang *config = pinconf_to_config_packed(param, arg); 51641d32cfcSBaolin Wang return 0; 51741d32cfcSBaolin Wang } 51841d32cfcSBaolin Wang 51941d32cfcSBaolin Wang static unsigned int sprd_pinconf_drive(unsigned int mA) 52041d32cfcSBaolin Wang { 52141d32cfcSBaolin Wang unsigned int val = 0; 52241d32cfcSBaolin Wang 52341d32cfcSBaolin Wang switch (mA) { 52441d32cfcSBaolin Wang case 2: 52541d32cfcSBaolin Wang break; 52641d32cfcSBaolin Wang case 4: 52741d32cfcSBaolin Wang val |= BIT(19); 52841d32cfcSBaolin Wang break; 52941d32cfcSBaolin Wang case 6: 53041d32cfcSBaolin Wang val |= BIT(20); 53141d32cfcSBaolin Wang break; 53241d32cfcSBaolin Wang case 8: 53341d32cfcSBaolin Wang val |= BIT(19) | BIT(20); 53441d32cfcSBaolin Wang break; 53541d32cfcSBaolin Wang case 10: 53641d32cfcSBaolin Wang val |= BIT(21); 53741d32cfcSBaolin Wang break; 53841d32cfcSBaolin Wang case 12: 53941d32cfcSBaolin Wang val |= BIT(21) | BIT(19); 54041d32cfcSBaolin Wang break; 54141d32cfcSBaolin Wang case 14: 54241d32cfcSBaolin Wang val |= BIT(21) | BIT(20); 54341d32cfcSBaolin Wang break; 54441d32cfcSBaolin Wang case 16: 54541d32cfcSBaolin Wang val |= BIT(19) | BIT(20) | BIT(21); 54641d32cfcSBaolin Wang break; 54741d32cfcSBaolin Wang case 20: 54841d32cfcSBaolin Wang val |= BIT(22); 54941d32cfcSBaolin Wang break; 55041d32cfcSBaolin Wang case 21: 55141d32cfcSBaolin Wang val |= BIT(22) | BIT(19); 55241d32cfcSBaolin Wang break; 55341d32cfcSBaolin Wang case 24: 55441d32cfcSBaolin Wang val |= BIT(22) | BIT(20); 55541d32cfcSBaolin Wang break; 55641d32cfcSBaolin Wang case 25: 55741d32cfcSBaolin Wang val |= BIT(22) | BIT(20) | BIT(19); 55841d32cfcSBaolin Wang break; 55941d32cfcSBaolin Wang case 27: 56041d32cfcSBaolin Wang val |= BIT(22) | BIT(21); 56141d32cfcSBaolin Wang break; 56241d32cfcSBaolin Wang case 29: 56341d32cfcSBaolin Wang val |= BIT(22) | BIT(21) | BIT(19); 56441d32cfcSBaolin Wang break; 56541d32cfcSBaolin Wang case 31: 56641d32cfcSBaolin Wang val |= BIT(22) | BIT(21) | BIT(20); 56741d32cfcSBaolin Wang break; 56841d32cfcSBaolin Wang case 33: 56941d32cfcSBaolin Wang val |= BIT(22) | BIT(21) | BIT(20) | BIT(19); 57041d32cfcSBaolin Wang break; 57141d32cfcSBaolin Wang default: 57241d32cfcSBaolin Wang break; 57341d32cfcSBaolin Wang } 57441d32cfcSBaolin Wang 57541d32cfcSBaolin Wang return val; 57641d32cfcSBaolin Wang } 57741d32cfcSBaolin Wang 57841d32cfcSBaolin Wang static bool sprd_pinctrl_check_sleep_config(unsigned long *configs, 57941d32cfcSBaolin Wang unsigned int num_configs) 58041d32cfcSBaolin Wang { 58141d32cfcSBaolin Wang unsigned int param; 58241d32cfcSBaolin Wang int i; 58341d32cfcSBaolin Wang 58441d32cfcSBaolin Wang for (i = 0; i < num_configs; i++) { 58541d32cfcSBaolin Wang param = pinconf_to_config_param(configs[i]); 58641d32cfcSBaolin Wang if (param == PIN_CONFIG_SLEEP_HARDWARE_STATE) 58741d32cfcSBaolin Wang return true; 58841d32cfcSBaolin Wang } 58941d32cfcSBaolin Wang 59041d32cfcSBaolin Wang return false; 59141d32cfcSBaolin Wang } 59241d32cfcSBaolin Wang 59341d32cfcSBaolin Wang static int sprd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id, 59441d32cfcSBaolin Wang unsigned long *configs, unsigned int num_configs) 59541d32cfcSBaolin Wang { 59641d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 59741d32cfcSBaolin Wang struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 59841d32cfcSBaolin Wang bool is_sleep_config; 59941d32cfcSBaolin Wang unsigned long reg; 60041d32cfcSBaolin Wang int i; 60141d32cfcSBaolin Wang 60241d32cfcSBaolin Wang if (!pin) 60341d32cfcSBaolin Wang return -EINVAL; 60441d32cfcSBaolin Wang 60541d32cfcSBaolin Wang is_sleep_config = sprd_pinctrl_check_sleep_config(configs, num_configs); 60641d32cfcSBaolin Wang 60741d32cfcSBaolin Wang for (i = 0; i < num_configs; i++) { 60841d32cfcSBaolin Wang unsigned int param, arg, shift, mask, val; 60941d32cfcSBaolin Wang 61041d32cfcSBaolin Wang param = pinconf_to_config_param(configs[i]); 61141d32cfcSBaolin Wang arg = pinconf_to_config_argument(configs[i]); 61241d32cfcSBaolin Wang 61341d32cfcSBaolin Wang val = 0; 61441d32cfcSBaolin Wang shift = 0; 61541d32cfcSBaolin Wang mask = 0; 61641d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN && 61741d32cfcSBaolin Wang param == SPRD_PIN_CONFIG_CONTROL) { 61841d32cfcSBaolin Wang val = arg; 6192f22e202SBaolin Wang } else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) { 62041d32cfcSBaolin Wang switch (param) { 62141d32cfcSBaolin Wang case SPRD_PIN_CONFIG_SLEEP_MODE: 62241d32cfcSBaolin Wang if (arg & AP_SLEEP) 62341d32cfcSBaolin Wang val |= AP_SLEEP_MODE; 62441d32cfcSBaolin Wang if (arg & PUBCP_SLEEP) 62541d32cfcSBaolin Wang val |= PUBCP_SLEEP_MODE; 62641d32cfcSBaolin Wang if (arg & TGLDSP_SLEEP) 62741d32cfcSBaolin Wang val |= TGLDSP_SLEEP_MODE; 62841d32cfcSBaolin Wang if (arg & AGDSP_SLEEP) 62941d32cfcSBaolin Wang val |= AGDSP_SLEEP_MODE; 630e543b3f5SBruce Chen if (arg & CM4_SLEEP) 631e543b3f5SBruce Chen val |= CM4_SLEEP_MODE; 63241d32cfcSBaolin Wang 63341d32cfcSBaolin Wang mask = SLEEP_MODE_MASK; 63441d32cfcSBaolin Wang shift = SLEEP_MODE_SHIFT; 63541d32cfcSBaolin Wang break; 63641d32cfcSBaolin Wang case PIN_CONFIG_INPUT_ENABLE: 63741d32cfcSBaolin Wang if (is_sleep_config == true) { 63841d32cfcSBaolin Wang if (arg > 0) 63941d32cfcSBaolin Wang val |= SLEEP_INPUT; 64041d32cfcSBaolin Wang else 64141d32cfcSBaolin Wang val &= ~SLEEP_INPUT; 64241d32cfcSBaolin Wang 64341d32cfcSBaolin Wang mask = SLEEP_INPUT_MASK; 64441d32cfcSBaolin Wang shift = SLEEP_INPUT_SHIFT; 64541d32cfcSBaolin Wang } 64641d32cfcSBaolin Wang break; 647bb0f472fSLinhua Xu case PIN_CONFIG_OUTPUT_ENABLE: 64841d32cfcSBaolin Wang if (is_sleep_config == true) { 649bb0f472fSLinhua Xu if (arg > 0) 65041d32cfcSBaolin Wang val |= SLEEP_OUTPUT; 651bb0f472fSLinhua Xu else 652bb0f472fSLinhua Xu val &= ~SLEEP_OUTPUT; 653bb0f472fSLinhua Xu 65441d32cfcSBaolin Wang mask = SLEEP_OUTPUT_MASK; 65541d32cfcSBaolin Wang shift = SLEEP_OUTPUT_SHIFT; 65641d32cfcSBaolin Wang } 65741d32cfcSBaolin Wang break; 6581592c4b9SLinhua Xu case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 6591592c4b9SLinhua Xu if (is_sleep_config == true) { 6601592c4b9SLinhua Xu val = shift = 0; 6611592c4b9SLinhua Xu mask = SLEEP_OUTPUT | SLEEP_INPUT; 6621592c4b9SLinhua Xu } 6631592c4b9SLinhua Xu break; 66441d32cfcSBaolin Wang case PIN_CONFIG_DRIVE_STRENGTH: 66541d32cfcSBaolin Wang if (arg < 2 || arg > 60) 66641d32cfcSBaolin Wang return -EINVAL; 66741d32cfcSBaolin Wang 66841d32cfcSBaolin Wang val = sprd_pinconf_drive(arg); 66941d32cfcSBaolin Wang mask = DRIVE_STRENGTH_MASK; 67041d32cfcSBaolin Wang shift = DRIVE_STRENGTH_SHIFT; 67141d32cfcSBaolin Wang break; 67241d32cfcSBaolin Wang case PIN_CONFIG_BIAS_PULL_DOWN: 67341d32cfcSBaolin Wang if (is_sleep_config == true) { 67441d32cfcSBaolin Wang val |= SLEEP_PULL_DOWN; 67541d32cfcSBaolin Wang mask = SLEEP_PULL_DOWN_MASK; 67641d32cfcSBaolin Wang shift = SLEEP_PULL_DOWN_SHIFT; 67741d32cfcSBaolin Wang } else { 67841d32cfcSBaolin Wang val |= PULL_DOWN; 67941d32cfcSBaolin Wang mask = PULL_DOWN_MASK; 68041d32cfcSBaolin Wang shift = PULL_DOWN_SHIFT; 68141d32cfcSBaolin Wang } 68241d32cfcSBaolin Wang break; 68341d32cfcSBaolin Wang case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 68441d32cfcSBaolin Wang if (arg > 0) 68541d32cfcSBaolin Wang val |= INPUT_SCHMITT; 68641d32cfcSBaolin Wang else 68741d32cfcSBaolin Wang val &= ~INPUT_SCHMITT; 68841d32cfcSBaolin Wang 68941d32cfcSBaolin Wang mask = INPUT_SCHMITT_MASK; 69041d32cfcSBaolin Wang shift = INPUT_SCHMITT_SHIFT; 69141d32cfcSBaolin Wang break; 69241d32cfcSBaolin Wang case PIN_CONFIG_BIAS_PULL_UP: 69360c456e0SYANG LI if (is_sleep_config) { 69441d32cfcSBaolin Wang val |= SLEEP_PULL_UP; 69541d32cfcSBaolin Wang mask = SLEEP_PULL_UP_MASK; 69641d32cfcSBaolin Wang shift = SLEEP_PULL_UP_SHIFT; 69741d32cfcSBaolin Wang } else { 69841d32cfcSBaolin Wang if (arg == 20000) 69941d32cfcSBaolin Wang val |= PULL_UP_20K; 70041d32cfcSBaolin Wang else if (arg == 4700) 70141d32cfcSBaolin Wang val |= PULL_UP_4_7K; 70241d32cfcSBaolin Wang 70341d32cfcSBaolin Wang mask = PULL_UP_MASK; 70441d32cfcSBaolin Wang shift = PULL_UP_SHIFT; 70541d32cfcSBaolin Wang } 70641d32cfcSBaolin Wang break; 707f8b05fe4SBaolin Wang case PIN_CONFIG_BIAS_DISABLE: 708f8b05fe4SBaolin Wang if (is_sleep_config == true) { 709f8b05fe4SBaolin Wang val = shift = 0; 710f8b05fe4SBaolin Wang mask = SLEEP_PULL_DOWN | SLEEP_PULL_UP; 711f8b05fe4SBaolin Wang } else { 712f8b05fe4SBaolin Wang val = shift = 0; 713f8b05fe4SBaolin Wang mask = PULL_DOWN | PULL_UP_20K | 714f8b05fe4SBaolin Wang PULL_UP_4_7K; 715f8b05fe4SBaolin Wang } 716f8b05fe4SBaolin Wang break; 71741d32cfcSBaolin Wang case PIN_CONFIG_SLEEP_HARDWARE_STATE: 71841d32cfcSBaolin Wang continue; 71941d32cfcSBaolin Wang default: 72041d32cfcSBaolin Wang return -ENOTSUPP; 72141d32cfcSBaolin Wang } 72241d32cfcSBaolin Wang } else { 72341d32cfcSBaolin Wang return -ENOTSUPP; 72441d32cfcSBaolin Wang } 72541d32cfcSBaolin Wang 72641d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN) { 72741d32cfcSBaolin Wang reg = readl((void __iomem *)pin->reg); 72841d32cfcSBaolin Wang reg &= ~(PINCTRL_BIT_MASK(pin->bit_width) 72941d32cfcSBaolin Wang << pin->bit_offset); 73041d32cfcSBaolin Wang reg |= (val & PINCTRL_BIT_MASK(pin->bit_width)) 73141d32cfcSBaolin Wang << pin->bit_offset; 73241d32cfcSBaolin Wang writel(reg, (void __iomem *)pin->reg); 73341d32cfcSBaolin Wang } else { 73441d32cfcSBaolin Wang reg = readl((void __iomem *)pin->reg); 73541d32cfcSBaolin Wang reg &= ~(mask << shift); 73641d32cfcSBaolin Wang reg |= val; 73741d32cfcSBaolin Wang writel(reg, (void __iomem *)pin->reg); 73841d32cfcSBaolin Wang } 73941d32cfcSBaolin Wang } 74041d32cfcSBaolin Wang 74141d32cfcSBaolin Wang return 0; 74241d32cfcSBaolin Wang } 74341d32cfcSBaolin Wang 74441d32cfcSBaolin Wang static int sprd_pinconf_group_get(struct pinctrl_dev *pctldev, 74541d32cfcSBaolin Wang unsigned int selector, unsigned long *config) 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 unsigned int pin_id; 75141d32cfcSBaolin Wang 7524ce504c4SDan Carpenter if (selector >= info->ngroups) 75341d32cfcSBaolin Wang return -EINVAL; 75441d32cfcSBaolin Wang 75541d32cfcSBaolin Wang grp = &info->groups[selector]; 75641d32cfcSBaolin Wang pin_id = grp->pins[0]; 75741d32cfcSBaolin Wang 75841d32cfcSBaolin Wang return sprd_pinconf_get(pctldev, pin_id, config); 75941d32cfcSBaolin Wang } 76041d32cfcSBaolin Wang 76141d32cfcSBaolin Wang static int sprd_pinconf_group_set(struct pinctrl_dev *pctldev, 76241d32cfcSBaolin Wang unsigned int selector, 76341d32cfcSBaolin Wang unsigned long *configs, 76441d32cfcSBaolin Wang unsigned int num_configs) 76541d32cfcSBaolin Wang { 76641d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 76741d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 76841d32cfcSBaolin Wang struct sprd_pin_group *grp; 76941d32cfcSBaolin Wang int ret, i; 77041d32cfcSBaolin Wang 7714ce504c4SDan Carpenter if (selector >= info->ngroups) 77241d32cfcSBaolin Wang return -EINVAL; 77341d32cfcSBaolin Wang 77441d32cfcSBaolin Wang grp = &info->groups[selector]; 77541d32cfcSBaolin Wang 77641d32cfcSBaolin Wang for (i = 0; i < grp->npins; i++) { 77741d32cfcSBaolin Wang unsigned int pin_id = grp->pins[i]; 77841d32cfcSBaolin Wang 77941d32cfcSBaolin Wang ret = sprd_pinconf_set(pctldev, pin_id, configs, num_configs); 78041d32cfcSBaolin Wang if (ret) 78141d32cfcSBaolin Wang return ret; 78241d32cfcSBaolin Wang } 78341d32cfcSBaolin Wang 78441d32cfcSBaolin Wang return 0; 78541d32cfcSBaolin Wang } 78641d32cfcSBaolin Wang 78741d32cfcSBaolin Wang static int sprd_pinconf_get_config(struct pinctrl_dev *pctldev, 78841d32cfcSBaolin Wang unsigned int pin_id, 78941d32cfcSBaolin Wang unsigned long *config) 79041d32cfcSBaolin Wang { 79141d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 79241d32cfcSBaolin Wang struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id); 79341d32cfcSBaolin Wang 79441d32cfcSBaolin Wang if (!pin) 79541d32cfcSBaolin Wang return -EINVAL; 79641d32cfcSBaolin Wang 79741d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN) { 79841d32cfcSBaolin Wang *config = (readl((void __iomem *)pin->reg) >> 79941d32cfcSBaolin Wang pin->bit_offset) & PINCTRL_BIT_MASK(pin->bit_width); 80041d32cfcSBaolin Wang } else { 80141d32cfcSBaolin Wang *config = readl((void __iomem *)pin->reg); 80241d32cfcSBaolin Wang } 80341d32cfcSBaolin Wang 80441d32cfcSBaolin Wang return 0; 80541d32cfcSBaolin Wang } 80641d32cfcSBaolin Wang 80741d32cfcSBaolin Wang static void sprd_pinconf_dbg_show(struct pinctrl_dev *pctldev, 80841d32cfcSBaolin Wang struct seq_file *s, unsigned int pin_id) 80941d32cfcSBaolin Wang { 81041d32cfcSBaolin Wang unsigned long config; 81141d32cfcSBaolin Wang int ret; 81241d32cfcSBaolin Wang 81341d32cfcSBaolin Wang ret = sprd_pinconf_get_config(pctldev, pin_id, &config); 81441d32cfcSBaolin Wang if (ret) 81541d32cfcSBaolin Wang return; 81641d32cfcSBaolin Wang 81741d32cfcSBaolin Wang seq_printf(s, "0x%lx", config); 81841d32cfcSBaolin Wang } 81941d32cfcSBaolin Wang 82041d32cfcSBaolin Wang static void sprd_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, 82141d32cfcSBaolin Wang struct seq_file *s, 82241d32cfcSBaolin Wang unsigned int selector) 82341d32cfcSBaolin Wang { 82441d32cfcSBaolin Wang struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 82541d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = pctl->info; 82641d32cfcSBaolin Wang struct sprd_pin_group *grp; 82741d32cfcSBaolin Wang unsigned long config; 82841d32cfcSBaolin Wang const char *name; 82941d32cfcSBaolin Wang int i, ret; 83041d32cfcSBaolin Wang 8314ce504c4SDan Carpenter if (selector >= info->ngroups) 83241d32cfcSBaolin Wang return; 83341d32cfcSBaolin Wang 83441d32cfcSBaolin Wang grp = &info->groups[selector]; 83541d32cfcSBaolin Wang 8369d2fc7c3SMarkus Elfring seq_putc(s, '\n'); 83741d32cfcSBaolin Wang for (i = 0; i < grp->npins; i++, config++) { 83841d32cfcSBaolin Wang unsigned int pin_id = grp->pins[i]; 83941d32cfcSBaolin Wang 84041d32cfcSBaolin Wang name = pin_get_name(pctldev, pin_id); 84141d32cfcSBaolin Wang ret = sprd_pinconf_get_config(pctldev, pin_id, &config); 84241d32cfcSBaolin Wang if (ret) 84341d32cfcSBaolin Wang return; 84441d32cfcSBaolin Wang 84541d32cfcSBaolin Wang seq_printf(s, "%s: 0x%lx ", name, config); 84641d32cfcSBaolin Wang } 84741d32cfcSBaolin Wang } 84841d32cfcSBaolin Wang 84941d32cfcSBaolin Wang static const struct pinconf_ops sprd_pinconf_ops = { 85041d32cfcSBaolin Wang .is_generic = true, 85141d32cfcSBaolin Wang .pin_config_get = sprd_pinconf_get, 85241d32cfcSBaolin Wang .pin_config_set = sprd_pinconf_set, 85341d32cfcSBaolin Wang .pin_config_group_get = sprd_pinconf_group_get, 85441d32cfcSBaolin Wang .pin_config_group_set = sprd_pinconf_group_set, 85541d32cfcSBaolin Wang .pin_config_dbg_show = sprd_pinconf_dbg_show, 85641d32cfcSBaolin Wang .pin_config_group_dbg_show = sprd_pinconf_group_dbg_show, 85741d32cfcSBaolin Wang }; 85841d32cfcSBaolin Wang 85941d32cfcSBaolin Wang static const struct pinconf_generic_params sprd_dt_params[] = { 86041d32cfcSBaolin Wang {"sprd,control", SPRD_PIN_CONFIG_CONTROL, 0}, 86141d32cfcSBaolin Wang {"sprd,sleep-mode", SPRD_PIN_CONFIG_SLEEP_MODE, 0}, 86241d32cfcSBaolin Wang }; 86341d32cfcSBaolin Wang 86441d32cfcSBaolin Wang #ifdef CONFIG_DEBUG_FS 86541d32cfcSBaolin Wang static const struct pin_config_item sprd_conf_items[] = { 86641d32cfcSBaolin Wang PCONFDUMP(SPRD_PIN_CONFIG_CONTROL, "global control", NULL, true), 86741d32cfcSBaolin Wang PCONFDUMP(SPRD_PIN_CONFIG_SLEEP_MODE, "sleep mode", NULL, true), 86841d32cfcSBaolin Wang }; 86941d32cfcSBaolin Wang #endif 87041d32cfcSBaolin Wang 87141d32cfcSBaolin Wang static struct pinctrl_desc sprd_pinctrl_desc = { 87241d32cfcSBaolin Wang .pctlops = &sprd_pctrl_ops, 87341d32cfcSBaolin Wang .pmxops = &sprd_pmx_ops, 87441d32cfcSBaolin Wang .confops = &sprd_pinconf_ops, 87541d32cfcSBaolin Wang .num_custom_params = ARRAY_SIZE(sprd_dt_params), 87641d32cfcSBaolin Wang .custom_params = sprd_dt_params, 87741d32cfcSBaolin Wang #ifdef CONFIG_DEBUG_FS 87841d32cfcSBaolin Wang .custom_conf_items = sprd_conf_items, 87941d32cfcSBaolin Wang #endif 88041d32cfcSBaolin Wang .owner = THIS_MODULE, 88141d32cfcSBaolin Wang }; 88241d32cfcSBaolin Wang 88341d32cfcSBaolin Wang static int sprd_pinctrl_parse_groups(struct device_node *np, 88441d32cfcSBaolin Wang struct sprd_pinctrl *sprd_pctl, 88541d32cfcSBaolin Wang struct sprd_pin_group *grp) 88641d32cfcSBaolin Wang { 88741d32cfcSBaolin Wang struct property *prop; 88841d32cfcSBaolin Wang const char *pin_name; 88941d32cfcSBaolin Wang int ret, i = 0; 89041d32cfcSBaolin Wang 89141d32cfcSBaolin Wang ret = of_property_count_strings(np, "pins"); 89241d32cfcSBaolin Wang if (ret < 0) 89341d32cfcSBaolin Wang return ret; 89441d32cfcSBaolin Wang 89541d32cfcSBaolin Wang grp->name = np->name; 89641d32cfcSBaolin Wang grp->npins = ret; 897a86854d0SKees Cook grp->pins = devm_kcalloc(sprd_pctl->dev, 898a86854d0SKees Cook grp->npins, sizeof(unsigned int), 899a86854d0SKees Cook GFP_KERNEL); 90041d32cfcSBaolin Wang if (!grp->pins) 90141d32cfcSBaolin Wang return -ENOMEM; 90241d32cfcSBaolin Wang 90341d32cfcSBaolin Wang of_property_for_each_string(np, "pins", prop, pin_name) { 90441d32cfcSBaolin Wang ret = sprd_pinctrl_get_id_by_name(sprd_pctl, pin_name); 90541d32cfcSBaolin Wang if (ret >= 0) 90641d32cfcSBaolin Wang grp->pins[i++] = ret; 90741d32cfcSBaolin Wang } 90841d32cfcSBaolin Wang 90941d32cfcSBaolin Wang for (i = 0; i < grp->npins; i++) { 91041d32cfcSBaolin Wang dev_dbg(sprd_pctl->dev, 91141d32cfcSBaolin Wang "Group[%s] contains [%d] pins: id = %d\n", 91241d32cfcSBaolin Wang grp->name, grp->npins, grp->pins[i]); 91341d32cfcSBaolin Wang } 91441d32cfcSBaolin Wang 91541d32cfcSBaolin Wang return 0; 91641d32cfcSBaolin Wang } 91741d32cfcSBaolin Wang 91841d32cfcSBaolin Wang static unsigned int sprd_pinctrl_get_groups(struct device_node *np) 91941d32cfcSBaolin Wang { 92041d32cfcSBaolin Wang struct device_node *child; 92141d32cfcSBaolin Wang unsigned int group_cnt, cnt; 92241d32cfcSBaolin Wang 92341d32cfcSBaolin Wang group_cnt = of_get_child_count(np); 92441d32cfcSBaolin Wang 92541d32cfcSBaolin Wang for_each_child_of_node(np, child) { 92641d32cfcSBaolin Wang cnt = of_get_child_count(child); 92741d32cfcSBaolin Wang if (cnt > 0) 92841d32cfcSBaolin Wang group_cnt += cnt; 92941d32cfcSBaolin Wang } 93041d32cfcSBaolin Wang 93141d32cfcSBaolin Wang return group_cnt; 93241d32cfcSBaolin Wang } 93341d32cfcSBaolin Wang 93441d32cfcSBaolin Wang static int sprd_pinctrl_parse_dt(struct sprd_pinctrl *sprd_pctl) 93541d32cfcSBaolin Wang { 93641d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 93741d32cfcSBaolin Wang struct device_node *np = sprd_pctl->dev->of_node; 93841d32cfcSBaolin Wang struct device_node *child, *sub_child; 93941d32cfcSBaolin Wang struct sprd_pin_group *grp; 94041d32cfcSBaolin Wang const char **temp; 94141d32cfcSBaolin Wang int ret; 94241d32cfcSBaolin Wang 94341d32cfcSBaolin Wang if (!np) 94441d32cfcSBaolin Wang return -ENODEV; 94541d32cfcSBaolin Wang 94641d32cfcSBaolin Wang info->ngroups = sprd_pinctrl_get_groups(np); 94741d32cfcSBaolin Wang if (!info->ngroups) 94841d32cfcSBaolin Wang return 0; 94941d32cfcSBaolin Wang 950a86854d0SKees Cook info->groups = devm_kcalloc(sprd_pctl->dev, 951a86854d0SKees Cook info->ngroups, 95241d32cfcSBaolin Wang sizeof(struct sprd_pin_group), 95341d32cfcSBaolin Wang GFP_KERNEL); 95441d32cfcSBaolin Wang if (!info->groups) 95541d32cfcSBaolin Wang return -ENOMEM; 95641d32cfcSBaolin Wang 957a86854d0SKees Cook info->grp_names = devm_kcalloc(sprd_pctl->dev, 958a86854d0SKees Cook info->ngroups, sizeof(char *), 95941d32cfcSBaolin Wang GFP_KERNEL); 96041d32cfcSBaolin Wang if (!info->grp_names) 96141d32cfcSBaolin Wang return -ENOMEM; 96241d32cfcSBaolin Wang 96341d32cfcSBaolin Wang temp = info->grp_names; 96441d32cfcSBaolin Wang grp = info->groups; 96541d32cfcSBaolin Wang 96641d32cfcSBaolin Wang for_each_child_of_node(np, child) { 96741d32cfcSBaolin Wang ret = sprd_pinctrl_parse_groups(child, sprd_pctl, grp); 9685a6bc290SNishka Dasgupta if (ret) { 9695a6bc290SNishka Dasgupta of_node_put(child); 97041d32cfcSBaolin Wang return ret; 9715a6bc290SNishka Dasgupta } 97241d32cfcSBaolin Wang 97341d32cfcSBaolin Wang *temp++ = grp->name; 97441d32cfcSBaolin Wang grp++; 97541d32cfcSBaolin Wang 97641d32cfcSBaolin Wang if (of_get_child_count(child) > 0) { 97741d32cfcSBaolin Wang for_each_child_of_node(child, sub_child) { 97841d32cfcSBaolin Wang ret = sprd_pinctrl_parse_groups(sub_child, 97941d32cfcSBaolin Wang sprd_pctl, grp); 9805a6bc290SNishka Dasgupta if (ret) { 9815a6bc290SNishka Dasgupta of_node_put(sub_child); 9825a6bc290SNishka Dasgupta of_node_put(child); 98341d32cfcSBaolin Wang return ret; 9845a6bc290SNishka Dasgupta } 98541d32cfcSBaolin Wang 98641d32cfcSBaolin Wang *temp++ = grp->name; 98741d32cfcSBaolin Wang grp++; 98841d32cfcSBaolin Wang } 98941d32cfcSBaolin Wang } 99041d32cfcSBaolin Wang } 99141d32cfcSBaolin Wang 99241d32cfcSBaolin Wang return 0; 99341d32cfcSBaolin Wang } 99441d32cfcSBaolin Wang 99541d32cfcSBaolin Wang static int sprd_pinctrl_add_pins(struct sprd_pinctrl *sprd_pctl, 99641d32cfcSBaolin Wang struct sprd_pins_info *sprd_soc_pin_info, 99741d32cfcSBaolin Wang int pins_cnt) 99841d32cfcSBaolin Wang { 99941d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *info = sprd_pctl->info; 100041d32cfcSBaolin Wang unsigned int ctrl_pin = 0, com_pin = 0; 100141d32cfcSBaolin Wang struct sprd_pin *pin; 100241d32cfcSBaolin Wang int i; 100341d32cfcSBaolin Wang 100441d32cfcSBaolin Wang info->npins = pins_cnt; 1005a86854d0SKees Cook info->pins = devm_kcalloc(sprd_pctl->dev, 1006a86854d0SKees Cook info->npins, sizeof(struct sprd_pin), 100741d32cfcSBaolin Wang GFP_KERNEL); 100841d32cfcSBaolin Wang if (!info->pins) 100941d32cfcSBaolin Wang return -ENOMEM; 101041d32cfcSBaolin Wang 101141d32cfcSBaolin Wang for (i = 0, pin = info->pins; i < info->npins; i++, pin++) { 101241d32cfcSBaolin Wang unsigned int reg; 101341d32cfcSBaolin Wang 101441d32cfcSBaolin Wang pin->name = sprd_soc_pin_info[i].name; 101541d32cfcSBaolin Wang pin->type = sprd_soc_pin_info[i].type; 101641d32cfcSBaolin Wang pin->number = sprd_soc_pin_info[i].num; 101741d32cfcSBaolin Wang reg = sprd_soc_pin_info[i].reg; 101841d32cfcSBaolin Wang if (pin->type == GLOBAL_CTRL_PIN) { 101941d32cfcSBaolin Wang pin->reg = (unsigned long)sprd_pctl->base + 102041d32cfcSBaolin Wang PINCTRL_REG_LEN * reg; 102141d32cfcSBaolin Wang pin->bit_offset = sprd_soc_pin_info[i].bit_offset; 102241d32cfcSBaolin Wang pin->bit_width = sprd_soc_pin_info[i].bit_width; 102341d32cfcSBaolin Wang ctrl_pin++; 102441d32cfcSBaolin Wang } else if (pin->type == COMMON_PIN) { 102541d32cfcSBaolin Wang pin->reg = (unsigned long)sprd_pctl->base + 102641d32cfcSBaolin Wang PINCTRL_REG_OFFSET + PINCTRL_REG_LEN * 102741d32cfcSBaolin Wang (i - ctrl_pin); 102841d32cfcSBaolin Wang com_pin++; 102941d32cfcSBaolin Wang } else if (pin->type == MISC_PIN) { 103041d32cfcSBaolin Wang pin->reg = (unsigned long)sprd_pctl->base + 103141d32cfcSBaolin Wang PINCTRL_REG_MISC_OFFSET + PINCTRL_REG_LEN * 103241d32cfcSBaolin Wang (i - ctrl_pin - com_pin); 103341d32cfcSBaolin Wang } 103441d32cfcSBaolin Wang } 103541d32cfcSBaolin Wang 103641d32cfcSBaolin Wang for (i = 0, pin = info->pins; i < info->npins; pin++, i++) { 103741d32cfcSBaolin Wang dev_dbg(sprd_pctl->dev, "pin name[%s-%d], type = %d, " 103841d32cfcSBaolin Wang "bit offset = %ld, bit width = %ld, reg = 0x%lx\n", 103941d32cfcSBaolin Wang pin->name, pin->number, pin->type, 104041d32cfcSBaolin Wang pin->bit_offset, pin->bit_width, pin->reg); 104141d32cfcSBaolin Wang } 104241d32cfcSBaolin Wang 104341d32cfcSBaolin Wang return 0; 104441d32cfcSBaolin Wang } 104541d32cfcSBaolin Wang 104641d32cfcSBaolin Wang int sprd_pinctrl_core_probe(struct platform_device *pdev, 104741d32cfcSBaolin Wang struct sprd_pins_info *sprd_soc_pin_info, 104841d32cfcSBaolin Wang int pins_cnt) 104941d32cfcSBaolin Wang { 105041d32cfcSBaolin Wang struct sprd_pinctrl *sprd_pctl; 105141d32cfcSBaolin Wang struct sprd_pinctrl_soc_info *pinctrl_info; 105241d32cfcSBaolin Wang struct pinctrl_pin_desc *pin_desc; 105341d32cfcSBaolin Wang int ret, i; 105441d32cfcSBaolin Wang 105541d32cfcSBaolin Wang sprd_pctl = devm_kzalloc(&pdev->dev, sizeof(struct sprd_pinctrl), 105641d32cfcSBaolin Wang GFP_KERNEL); 105741d32cfcSBaolin Wang if (!sprd_pctl) 105841d32cfcSBaolin Wang return -ENOMEM; 105941d32cfcSBaolin Wang 1060e89febc7SBaolin Wang sprd_pctl->base = devm_platform_ioremap_resource(pdev, 0); 106141d32cfcSBaolin Wang if (IS_ERR(sprd_pctl->base)) 106241d32cfcSBaolin Wang return PTR_ERR(sprd_pctl->base); 106341d32cfcSBaolin Wang 106441d32cfcSBaolin Wang pinctrl_info = devm_kzalloc(&pdev->dev, 106541d32cfcSBaolin Wang sizeof(struct sprd_pinctrl_soc_info), 106641d32cfcSBaolin Wang GFP_KERNEL); 106741d32cfcSBaolin Wang if (!pinctrl_info) 106841d32cfcSBaolin Wang return -ENOMEM; 106941d32cfcSBaolin Wang 107041d32cfcSBaolin Wang sprd_pctl->info = pinctrl_info; 107141d32cfcSBaolin Wang sprd_pctl->dev = &pdev->dev; 107241d32cfcSBaolin Wang platform_set_drvdata(pdev, sprd_pctl); 107341d32cfcSBaolin Wang 107441d32cfcSBaolin Wang ret = sprd_pinctrl_add_pins(sprd_pctl, sprd_soc_pin_info, pins_cnt); 107541d32cfcSBaolin Wang if (ret) { 107641d32cfcSBaolin Wang dev_err(&pdev->dev, "fail to add pins information\n"); 107741d32cfcSBaolin Wang return ret; 107841d32cfcSBaolin Wang } 107941d32cfcSBaolin Wang 108063e037bcSBaolin Wang ret = sprd_pinctrl_parse_dt(sprd_pctl); 108163e037bcSBaolin Wang if (ret) { 108263e037bcSBaolin Wang dev_err(&pdev->dev, "fail to parse dt properties\n"); 108363e037bcSBaolin Wang return ret; 108463e037bcSBaolin Wang } 108563e037bcSBaolin Wang 1086a86854d0SKees Cook pin_desc = devm_kcalloc(&pdev->dev, 1087a86854d0SKees Cook pinctrl_info->npins, 108841d32cfcSBaolin Wang sizeof(struct pinctrl_pin_desc), 108941d32cfcSBaolin Wang GFP_KERNEL); 109041d32cfcSBaolin Wang if (!pin_desc) 109141d32cfcSBaolin Wang return -ENOMEM; 109241d32cfcSBaolin Wang 109341d32cfcSBaolin Wang for (i = 0; i < pinctrl_info->npins; i++) { 109441d32cfcSBaolin Wang pin_desc[i].number = pinctrl_info->pins[i].number; 109541d32cfcSBaolin Wang pin_desc[i].name = pinctrl_info->pins[i].name; 109641d32cfcSBaolin Wang pin_desc[i].drv_data = pinctrl_info; 109741d32cfcSBaolin Wang } 109841d32cfcSBaolin Wang 109941d32cfcSBaolin Wang sprd_pinctrl_desc.pins = pin_desc; 110041d32cfcSBaolin Wang sprd_pinctrl_desc.name = dev_name(&pdev->dev); 110141d32cfcSBaolin Wang sprd_pinctrl_desc.npins = pinctrl_info->npins; 110241d32cfcSBaolin Wang 110341d32cfcSBaolin Wang sprd_pctl->pctl = pinctrl_register(&sprd_pinctrl_desc, 110441d32cfcSBaolin Wang &pdev->dev, (void *)sprd_pctl); 110541d32cfcSBaolin Wang if (IS_ERR(sprd_pctl->pctl)) { 110641d32cfcSBaolin Wang dev_err(&pdev->dev, "could not register pinctrl driver\n"); 110741d32cfcSBaolin Wang return PTR_ERR(sprd_pctl->pctl); 110841d32cfcSBaolin Wang } 110941d32cfcSBaolin Wang 111041d32cfcSBaolin Wang return 0; 111141d32cfcSBaolin Wang } 11121df49cc8SBaolin Wang EXPORT_SYMBOL_GPL(sprd_pinctrl_core_probe); 111341d32cfcSBaolin Wang 111441d32cfcSBaolin Wang int sprd_pinctrl_remove(struct platform_device *pdev) 111541d32cfcSBaolin Wang { 111641d32cfcSBaolin Wang struct sprd_pinctrl *sprd_pctl = platform_get_drvdata(pdev); 111741d32cfcSBaolin Wang 111841d32cfcSBaolin Wang pinctrl_unregister(sprd_pctl->pctl); 111941d32cfcSBaolin Wang return 0; 112041d32cfcSBaolin Wang } 11211df49cc8SBaolin Wang EXPORT_SYMBOL_GPL(sprd_pinctrl_remove); 112241d32cfcSBaolin Wang 112341d32cfcSBaolin Wang void sprd_pinctrl_shutdown(struct platform_device *pdev) 112441d32cfcSBaolin Wang { 112541470c37SDan Carpenter struct pinctrl *pinctl; 112641d32cfcSBaolin Wang struct pinctrl_state *state; 112741d32cfcSBaolin Wang 112841470c37SDan Carpenter pinctl = devm_pinctrl_get(&pdev->dev); 112941470c37SDan Carpenter if (IS_ERR(pinctl)) 113041470c37SDan Carpenter return; 113141d32cfcSBaolin Wang state = pinctrl_lookup_state(pinctl, "shutdown"); 113241470c37SDan Carpenter if (IS_ERR(state)) 113341470c37SDan Carpenter return; 113441d32cfcSBaolin Wang pinctrl_select_state(pinctl, state); 113541d32cfcSBaolin Wang } 11361df49cc8SBaolin Wang EXPORT_SYMBOL_GPL(sprd_pinctrl_shutdown); 113741d32cfcSBaolin Wang 113841d32cfcSBaolin Wang MODULE_DESCRIPTION("SPREADTRUM Pin Controller Driver"); 113941d32cfcSBaolin Wang MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>"); 114041d32cfcSBaolin Wang MODULE_LICENSE("GPL v2"); 1141