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