162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Pinctrl driver for the Wondermedia SoC's 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/err.h> 962306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/irq.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/of_irq.h> 1562306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1662306a36Sopenharmony_ci#include <linux/pinctrl/machine.h> 1762306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 1862306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 1962306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 2062306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 2162306a36Sopenharmony_ci#include <linux/platform_device.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "pinctrl-wmt.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic inline void wmt_setbits(struct wmt_pinctrl_data *data, u32 reg, 2762306a36Sopenharmony_ci u32 mask) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci u32 val; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci val = readl_relaxed(data->base + reg); 3262306a36Sopenharmony_ci val |= mask; 3362306a36Sopenharmony_ci writel_relaxed(val, data->base + reg); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic inline void wmt_clearbits(struct wmt_pinctrl_data *data, u32 reg, 3762306a36Sopenharmony_ci u32 mask) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci u32 val; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci val = readl_relaxed(data->base + reg); 4262306a36Sopenharmony_ci val &= ~mask; 4362306a36Sopenharmony_ci writel_relaxed(val, data->base + reg); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cienum wmt_func_sel { 4762306a36Sopenharmony_ci WMT_FSEL_GPIO_IN = 0, 4862306a36Sopenharmony_ci WMT_FSEL_GPIO_OUT = 1, 4962306a36Sopenharmony_ci WMT_FSEL_ALT = 2, 5062306a36Sopenharmony_ci WMT_FSEL_COUNT = 3, 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const char * const wmt_functions[WMT_FSEL_COUNT] = { 5462306a36Sopenharmony_ci [WMT_FSEL_GPIO_IN] = "gpio_in", 5562306a36Sopenharmony_ci [WMT_FSEL_GPIO_OUT] = "gpio_out", 5662306a36Sopenharmony_ci [WMT_FSEL_ALT] = "alt", 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int wmt_pmx_get_functions_count(struct pinctrl_dev *pctldev) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci return WMT_FSEL_COUNT; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic const char *wmt_pmx_get_function_name(struct pinctrl_dev *pctldev, 6562306a36Sopenharmony_ci unsigned selector) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci return wmt_functions[selector]; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int wmt_pmx_get_function_groups(struct pinctrl_dev *pctldev, 7162306a36Sopenharmony_ci unsigned selector, 7262306a36Sopenharmony_ci const char * const **groups, 7362306a36Sopenharmony_ci unsigned * const num_groups) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* every pin does every function */ 7862306a36Sopenharmony_ci *groups = data->groups; 7962306a36Sopenharmony_ci *num_groups = data->ngroups; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int wmt_set_pinmux(struct wmt_pinctrl_data *data, unsigned func, 8562306a36Sopenharmony_ci unsigned pin) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci u32 bank = WMT_BANK_FROM_PIN(pin); 8862306a36Sopenharmony_ci u32 bit = WMT_BIT_FROM_PIN(pin); 8962306a36Sopenharmony_ci u32 reg_en = data->banks[bank].reg_en; 9062306a36Sopenharmony_ci u32 reg_dir = data->banks[bank].reg_dir; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (reg_dir == NO_REG) { 9362306a36Sopenharmony_ci dev_err(data->dev, "pin:%d no direction register defined\n", 9462306a36Sopenharmony_ci pin); 9562306a36Sopenharmony_ci return -EINVAL; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* 9962306a36Sopenharmony_ci * If reg_en == NO_REG, we assume it is a dedicated GPIO and cannot be 10062306a36Sopenharmony_ci * disabled (as on VT8500) and that no alternate function is available. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci switch (func) { 10362306a36Sopenharmony_ci case WMT_FSEL_GPIO_IN: 10462306a36Sopenharmony_ci if (reg_en != NO_REG) 10562306a36Sopenharmony_ci wmt_setbits(data, reg_en, BIT(bit)); 10662306a36Sopenharmony_ci wmt_clearbits(data, reg_dir, BIT(bit)); 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci case WMT_FSEL_GPIO_OUT: 10962306a36Sopenharmony_ci if (reg_en != NO_REG) 11062306a36Sopenharmony_ci wmt_setbits(data, reg_en, BIT(bit)); 11162306a36Sopenharmony_ci wmt_setbits(data, reg_dir, BIT(bit)); 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci case WMT_FSEL_ALT: 11462306a36Sopenharmony_ci if (reg_en == NO_REG) { 11562306a36Sopenharmony_ci dev_err(data->dev, "pin:%d no alt function available\n", 11662306a36Sopenharmony_ci pin); 11762306a36Sopenharmony_ci return -EINVAL; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci wmt_clearbits(data, reg_en, BIT(bit)); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int wmt_pmx_set_mux(struct pinctrl_dev *pctldev, 12662306a36Sopenharmony_ci unsigned func_selector, 12762306a36Sopenharmony_ci unsigned group_selector) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); 13062306a36Sopenharmony_ci u32 pinnum = data->pins[group_selector].number; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return wmt_set_pinmux(data, func_selector, pinnum); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void wmt_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, 13662306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 13762306a36Sopenharmony_ci unsigned offset) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* disable by setting GPIO_IN */ 14262306a36Sopenharmony_ci wmt_set_pinmux(data, WMT_FSEL_GPIO_IN, offset); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int wmt_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 14662306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 14762306a36Sopenharmony_ci unsigned offset, 14862306a36Sopenharmony_ci bool input) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci wmt_set_pinmux(data, (input ? WMT_FSEL_GPIO_IN : WMT_FSEL_GPIO_OUT), 15362306a36Sopenharmony_ci offset); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic const struct pinmux_ops wmt_pinmux_ops = { 15962306a36Sopenharmony_ci .get_functions_count = wmt_pmx_get_functions_count, 16062306a36Sopenharmony_ci .get_function_name = wmt_pmx_get_function_name, 16162306a36Sopenharmony_ci .get_function_groups = wmt_pmx_get_function_groups, 16262306a36Sopenharmony_ci .set_mux = wmt_pmx_set_mux, 16362306a36Sopenharmony_ci .gpio_disable_free = wmt_pmx_gpio_disable_free, 16462306a36Sopenharmony_ci .gpio_set_direction = wmt_pmx_gpio_set_direction, 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int wmt_get_groups_count(struct pinctrl_dev *pctldev) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return data->ngroups; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic const char *wmt_get_group_name(struct pinctrl_dev *pctldev, 17562306a36Sopenharmony_ci unsigned selector) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return data->groups[selector]; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int wmt_get_group_pins(struct pinctrl_dev *pctldev, 18362306a36Sopenharmony_ci unsigned selector, 18462306a36Sopenharmony_ci const unsigned **pins, 18562306a36Sopenharmony_ci unsigned *num_pins) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci *pins = &data->pins[selector].number; 19062306a36Sopenharmony_ci *num_pins = 1; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int wmt_pctl_find_group_by_pin(struct wmt_pinctrl_data *data, u32 pin) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci int i; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci for (i = 0; i < data->npins; i++) { 20062306a36Sopenharmony_ci if (data->pins[i].number == pin) 20162306a36Sopenharmony_ci return i; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return -EINVAL; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int wmt_pctl_dt_node_to_map_func(struct wmt_pinctrl_data *data, 20862306a36Sopenharmony_ci struct device_node *np, 20962306a36Sopenharmony_ci u32 pin, u32 fnum, 21062306a36Sopenharmony_ci struct pinctrl_map **maps) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci int group; 21362306a36Sopenharmony_ci struct pinctrl_map *map = *maps; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (fnum >= ARRAY_SIZE(wmt_functions)) { 21662306a36Sopenharmony_ci dev_err(data->dev, "invalid wm,function %d\n", fnum); 21762306a36Sopenharmony_ci return -EINVAL; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci group = wmt_pctl_find_group_by_pin(data, pin); 22162306a36Sopenharmony_ci if (group < 0) { 22262306a36Sopenharmony_ci dev_err(data->dev, "unable to match pin %d to group\n", pin); 22362306a36Sopenharmony_ci return group; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci map->type = PIN_MAP_TYPE_MUX_GROUP; 22762306a36Sopenharmony_ci map->data.mux.group = data->groups[group]; 22862306a36Sopenharmony_ci map->data.mux.function = wmt_functions[fnum]; 22962306a36Sopenharmony_ci (*maps)++; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic int wmt_pctl_dt_node_to_map_pull(struct wmt_pinctrl_data *data, 23562306a36Sopenharmony_ci struct device_node *np, 23662306a36Sopenharmony_ci u32 pin, u32 pull, 23762306a36Sopenharmony_ci struct pinctrl_map **maps) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int group; 24062306a36Sopenharmony_ci unsigned long *configs; 24162306a36Sopenharmony_ci struct pinctrl_map *map = *maps; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (pull > 2) { 24462306a36Sopenharmony_ci dev_err(data->dev, "invalid wm,pull %d\n", pull); 24562306a36Sopenharmony_ci return -EINVAL; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci group = wmt_pctl_find_group_by_pin(data, pin); 24962306a36Sopenharmony_ci if (group < 0) { 25062306a36Sopenharmony_ci dev_err(data->dev, "unable to match pin %d to group\n", pin); 25162306a36Sopenharmony_ci return group; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci configs = kzalloc(sizeof(*configs), GFP_KERNEL); 25562306a36Sopenharmony_ci if (!configs) 25662306a36Sopenharmony_ci return -ENOMEM; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci switch (pull) { 25962306a36Sopenharmony_ci case 0: 26062306a36Sopenharmony_ci configs[0] = PIN_CONFIG_BIAS_DISABLE; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci case 1: 26362306a36Sopenharmony_ci configs[0] = PIN_CONFIG_BIAS_PULL_DOWN; 26462306a36Sopenharmony_ci break; 26562306a36Sopenharmony_ci case 2: 26662306a36Sopenharmony_ci configs[0] = PIN_CONFIG_BIAS_PULL_UP; 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci default: 26962306a36Sopenharmony_ci configs[0] = PIN_CONFIG_BIAS_DISABLE; 27062306a36Sopenharmony_ci dev_err(data->dev, "invalid pull state %d - disabling\n", pull); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci map->type = PIN_MAP_TYPE_CONFIGS_PIN; 27462306a36Sopenharmony_ci map->data.configs.group_or_pin = data->groups[group]; 27562306a36Sopenharmony_ci map->data.configs.configs = configs; 27662306a36Sopenharmony_ci map->data.configs.num_configs = 1; 27762306a36Sopenharmony_ci (*maps)++; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic void wmt_pctl_dt_free_map(struct pinctrl_dev *pctldev, 28362306a36Sopenharmony_ci struct pinctrl_map *maps, 28462306a36Sopenharmony_ci unsigned num_maps) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int i; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci for (i = 0; i < num_maps; i++) 28962306a36Sopenharmony_ci if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN) 29062306a36Sopenharmony_ci kfree(maps[i].data.configs.configs); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci kfree(maps); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int wmt_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, 29662306a36Sopenharmony_ci struct device_node *np, 29762306a36Sopenharmony_ci struct pinctrl_map **map, 29862306a36Sopenharmony_ci unsigned *num_maps) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct pinctrl_map *maps, *cur_map; 30162306a36Sopenharmony_ci struct property *pins, *funcs, *pulls; 30262306a36Sopenharmony_ci u32 pin, func, pull; 30362306a36Sopenharmony_ci int num_pins, num_funcs, num_pulls, maps_per_pin; 30462306a36Sopenharmony_ci int i, err; 30562306a36Sopenharmony_ci struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci pins = of_find_property(np, "wm,pins", NULL); 30862306a36Sopenharmony_ci if (!pins) { 30962306a36Sopenharmony_ci dev_err(data->dev, "missing wmt,pins property\n"); 31062306a36Sopenharmony_ci return -EINVAL; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci funcs = of_find_property(np, "wm,function", NULL); 31462306a36Sopenharmony_ci pulls = of_find_property(np, "wm,pull", NULL); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (!funcs && !pulls) { 31762306a36Sopenharmony_ci dev_err(data->dev, "neither wm,function nor wm,pull specified\n"); 31862306a36Sopenharmony_ci return -EINVAL; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* 32262306a36Sopenharmony_ci * The following lines calculate how many values are defined for each 32362306a36Sopenharmony_ci * of the properties. 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ci num_pins = pins->length / sizeof(u32); 32662306a36Sopenharmony_ci num_funcs = funcs ? (funcs->length / sizeof(u32)) : 0; 32762306a36Sopenharmony_ci num_pulls = pulls ? (pulls->length / sizeof(u32)) : 0; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (num_funcs > 1 && num_funcs != num_pins) { 33062306a36Sopenharmony_ci dev_err(data->dev, "wm,function must have 1 or %d entries\n", 33162306a36Sopenharmony_ci num_pins); 33262306a36Sopenharmony_ci return -EINVAL; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (num_pulls > 1 && num_pulls != num_pins) { 33662306a36Sopenharmony_ci dev_err(data->dev, "wm,pull must have 1 or %d entries\n", 33762306a36Sopenharmony_ci num_pins); 33862306a36Sopenharmony_ci return -EINVAL; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci maps_per_pin = 0; 34262306a36Sopenharmony_ci if (num_funcs) 34362306a36Sopenharmony_ci maps_per_pin++; 34462306a36Sopenharmony_ci if (num_pulls) 34562306a36Sopenharmony_ci maps_per_pin++; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci cur_map = maps = kcalloc(num_pins * maps_per_pin, sizeof(*maps), 34862306a36Sopenharmony_ci GFP_KERNEL); 34962306a36Sopenharmony_ci if (!maps) 35062306a36Sopenharmony_ci return -ENOMEM; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci for (i = 0; i < num_pins; i++) { 35362306a36Sopenharmony_ci err = of_property_read_u32_index(np, "wm,pins", i, &pin); 35462306a36Sopenharmony_ci if (err) 35562306a36Sopenharmony_ci goto fail; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (pin >= (data->nbanks * 32)) { 35862306a36Sopenharmony_ci dev_err(data->dev, "invalid wm,pins value\n"); 35962306a36Sopenharmony_ci err = -EINVAL; 36062306a36Sopenharmony_ci goto fail; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (num_funcs) { 36462306a36Sopenharmony_ci err = of_property_read_u32_index(np, "wm,function", 36562306a36Sopenharmony_ci (num_funcs > 1 ? i : 0), &func); 36662306a36Sopenharmony_ci if (err) 36762306a36Sopenharmony_ci goto fail; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci err = wmt_pctl_dt_node_to_map_func(data, np, pin, func, 37062306a36Sopenharmony_ci &cur_map); 37162306a36Sopenharmony_ci if (err) 37262306a36Sopenharmony_ci goto fail; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (num_pulls) { 37662306a36Sopenharmony_ci err = of_property_read_u32_index(np, "wm,pull", 37762306a36Sopenharmony_ci (num_pulls > 1 ? i : 0), &pull); 37862306a36Sopenharmony_ci if (err) 37962306a36Sopenharmony_ci goto fail; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci err = wmt_pctl_dt_node_to_map_pull(data, np, pin, pull, 38262306a36Sopenharmony_ci &cur_map); 38362306a36Sopenharmony_ci if (err) 38462306a36Sopenharmony_ci goto fail; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci *map = maps; 38862306a36Sopenharmony_ci *num_maps = num_pins * maps_per_pin; 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci/* 39262306a36Sopenharmony_ci * The fail path removes any maps that have been allocated. The fail path is 39362306a36Sopenharmony_ci * only called from code after maps has been kzalloc'd. It is also safe to 39462306a36Sopenharmony_ci * pass 'num_pins * maps_per_pin' as the map count even though we probably 39562306a36Sopenharmony_ci * failed before all the mappings were read as all maps are allocated at once, 39662306a36Sopenharmony_ci * and configs are only allocated for .type = PIN_MAP_TYPE_CONFIGS_PIN - there 39762306a36Sopenharmony_ci * is no failpath where a config can be allocated without .type being set. 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_cifail: 40062306a36Sopenharmony_ci wmt_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin); 40162306a36Sopenharmony_ci return err; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic const struct pinctrl_ops wmt_pctl_ops = { 40562306a36Sopenharmony_ci .get_groups_count = wmt_get_groups_count, 40662306a36Sopenharmony_ci .get_group_name = wmt_get_group_name, 40762306a36Sopenharmony_ci .get_group_pins = wmt_get_group_pins, 40862306a36Sopenharmony_ci .dt_node_to_map = wmt_pctl_dt_node_to_map, 40962306a36Sopenharmony_ci .dt_free_map = wmt_pctl_dt_free_map, 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int wmt_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, 41362306a36Sopenharmony_ci unsigned long *config) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci return -ENOTSUPP; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, 41962306a36Sopenharmony_ci unsigned long *configs, unsigned num_configs) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); 42262306a36Sopenharmony_ci enum pin_config_param param; 42362306a36Sopenharmony_ci u32 arg; 42462306a36Sopenharmony_ci u32 bank = WMT_BANK_FROM_PIN(pin); 42562306a36Sopenharmony_ci u32 bit = WMT_BIT_FROM_PIN(pin); 42662306a36Sopenharmony_ci u32 reg_pull_en = data->banks[bank].reg_pull_en; 42762306a36Sopenharmony_ci u32 reg_pull_cfg = data->banks[bank].reg_pull_cfg; 42862306a36Sopenharmony_ci int i; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if ((reg_pull_en == NO_REG) || (reg_pull_cfg == NO_REG)) { 43162306a36Sopenharmony_ci dev_err(data->dev, "bias functions not supported on pin %d\n", 43262306a36Sopenharmony_ci pin); 43362306a36Sopenharmony_ci return -EINVAL; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 43762306a36Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 43862306a36Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if ((param == PIN_CONFIG_BIAS_PULL_DOWN) || 44162306a36Sopenharmony_ci (param == PIN_CONFIG_BIAS_PULL_UP)) { 44262306a36Sopenharmony_ci if (arg == 0) 44362306a36Sopenharmony_ci param = PIN_CONFIG_BIAS_DISABLE; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci switch (param) { 44762306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 44862306a36Sopenharmony_ci wmt_clearbits(data, reg_pull_en, BIT(bit)); 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 45162306a36Sopenharmony_ci wmt_clearbits(data, reg_pull_cfg, BIT(bit)); 45262306a36Sopenharmony_ci wmt_setbits(data, reg_pull_en, BIT(bit)); 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 45562306a36Sopenharmony_ci wmt_setbits(data, reg_pull_cfg, BIT(bit)); 45662306a36Sopenharmony_ci wmt_setbits(data, reg_pull_en, BIT(bit)); 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci default: 45962306a36Sopenharmony_ci dev_err(data->dev, "unknown pinconf param\n"); 46062306a36Sopenharmony_ci return -EINVAL; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci } /* for each config */ 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic const struct pinconf_ops wmt_pinconf_ops = { 46862306a36Sopenharmony_ci .pin_config_get = wmt_pinconf_get, 46962306a36Sopenharmony_ci .pin_config_set = wmt_pinconf_set, 47062306a36Sopenharmony_ci}; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic struct pinctrl_desc wmt_desc = { 47362306a36Sopenharmony_ci .owner = THIS_MODULE, 47462306a36Sopenharmony_ci .name = "pinctrl-wmt", 47562306a36Sopenharmony_ci .pctlops = &wmt_pctl_ops, 47662306a36Sopenharmony_ci .pmxops = &wmt_pinmux_ops, 47762306a36Sopenharmony_ci .confops = &wmt_pinconf_ops, 47862306a36Sopenharmony_ci}; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct wmt_pinctrl_data *data = gpiochip_get_data(chip); 48362306a36Sopenharmony_ci u32 bank = WMT_BANK_FROM_PIN(offset); 48462306a36Sopenharmony_ci u32 bit = WMT_BIT_FROM_PIN(offset); 48562306a36Sopenharmony_ci u32 reg_dir = data->banks[bank].reg_dir; 48662306a36Sopenharmony_ci u32 val; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci val = readl_relaxed(data->base + reg_dir); 48962306a36Sopenharmony_ci if (val & BIT(bit)) 49062306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci struct wmt_pinctrl_data *data = gpiochip_get_data(chip); 49862306a36Sopenharmony_ci u32 bank = WMT_BANK_FROM_PIN(offset); 49962306a36Sopenharmony_ci u32 bit = WMT_BIT_FROM_PIN(offset); 50062306a36Sopenharmony_ci u32 reg_data_in = data->banks[bank].reg_data_in; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (reg_data_in == NO_REG) { 50362306a36Sopenharmony_ci dev_err(data->dev, "no data in register defined\n"); 50462306a36Sopenharmony_ci return -EINVAL; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return !!(readl_relaxed(data->base + reg_data_in) & BIT(bit)); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset, 51162306a36Sopenharmony_ci int val) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci struct wmt_pinctrl_data *data = gpiochip_get_data(chip); 51462306a36Sopenharmony_ci u32 bank = WMT_BANK_FROM_PIN(offset); 51562306a36Sopenharmony_ci u32 bit = WMT_BIT_FROM_PIN(offset); 51662306a36Sopenharmony_ci u32 reg_data_out = data->banks[bank].reg_data_out; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (reg_data_out == NO_REG) { 51962306a36Sopenharmony_ci dev_err(data->dev, "no data out register defined\n"); 52062306a36Sopenharmony_ci return; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (val) 52462306a36Sopenharmony_ci wmt_setbits(data, reg_data_out, BIT(bit)); 52562306a36Sopenharmony_ci else 52662306a36Sopenharmony_ci wmt_clearbits(data, reg_data_out, BIT(bit)); 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int wmt_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci return pinctrl_gpio_direction_input(chip->base + offset); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int wmt_gpio_direction_output(struct gpio_chip *chip, unsigned offset, 53562306a36Sopenharmony_ci int value) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci wmt_gpio_set_value(chip, offset, value); 53862306a36Sopenharmony_ci return pinctrl_gpio_direction_output(chip->base + offset); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic const struct gpio_chip wmt_gpio_chip = { 54262306a36Sopenharmony_ci .label = "gpio-wmt", 54362306a36Sopenharmony_ci .owner = THIS_MODULE, 54462306a36Sopenharmony_ci .request = gpiochip_generic_request, 54562306a36Sopenharmony_ci .free = gpiochip_generic_free, 54662306a36Sopenharmony_ci .get_direction = wmt_gpio_get_direction, 54762306a36Sopenharmony_ci .direction_input = wmt_gpio_direction_input, 54862306a36Sopenharmony_ci .direction_output = wmt_gpio_direction_output, 54962306a36Sopenharmony_ci .get = wmt_gpio_get_value, 55062306a36Sopenharmony_ci .set = wmt_gpio_set_value, 55162306a36Sopenharmony_ci .can_sleep = false, 55262306a36Sopenharmony_ci}; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ciint wmt_pinctrl_probe(struct platform_device *pdev, 55562306a36Sopenharmony_ci struct wmt_pinctrl_data *data) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci int err; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci data->base = devm_platform_ioremap_resource(pdev, 0); 56062306a36Sopenharmony_ci if (IS_ERR(data->base)) 56162306a36Sopenharmony_ci return PTR_ERR(data->base); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci wmt_desc.pins = data->pins; 56462306a36Sopenharmony_ci wmt_desc.npins = data->npins; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci data->gpio_chip = wmt_gpio_chip; 56762306a36Sopenharmony_ci data->gpio_chip.parent = &pdev->dev; 56862306a36Sopenharmony_ci data->gpio_chip.ngpio = data->nbanks * 32; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci platform_set_drvdata(pdev, data); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci data->dev = &pdev->dev; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci data->pctl_dev = devm_pinctrl_register(&pdev->dev, &wmt_desc, data); 57562306a36Sopenharmony_ci if (IS_ERR(data->pctl_dev)) { 57662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register pinctrl\n"); 57762306a36Sopenharmony_ci return PTR_ERR(data->pctl_dev); 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci err = gpiochip_add_data(&data->gpio_chip, data); 58162306a36Sopenharmony_ci if (err) { 58262306a36Sopenharmony_ci dev_err(&pdev->dev, "could not add GPIO chip\n"); 58362306a36Sopenharmony_ci return err; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci err = gpiochip_add_pin_range(&data->gpio_chip, dev_name(data->dev), 58762306a36Sopenharmony_ci 0, 0, data->nbanks * 32); 58862306a36Sopenharmony_ci if (err) 58962306a36Sopenharmony_ci goto fail_range; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci dev_info(&pdev->dev, "Pin controller initialized\n"); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci return 0; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cifail_range: 59662306a36Sopenharmony_ci gpiochip_remove(&data->gpio_chip); 59762306a36Sopenharmony_ci return err; 59862306a36Sopenharmony_ci} 599