1*cb703792SJia Wang // SPDX-License-Identifier: GPL-2.0 2*cb703792SJia Wang /* 3*cb703792SJia Wang * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. 4*cb703792SJia Wang * 5*cb703792SJia Wang * Author: Jia Wang <wangjia@ultrarisc.com> 6*cb703792SJia Wang */ 7*cb703792SJia Wang 8*cb703792SJia Wang #include <linux/bitfield.h> 9*cb703792SJia Wang #include <linux/io.h> 10*cb703792SJia Wang #include <linux/module.h> 11*cb703792SJia Wang #include <linux/pinctrl/pinconf.h> 12*cb703792SJia Wang #include <linux/pinctrl/pinconf-generic.h> 13*cb703792SJia Wang #include <linux/pinctrl/pinmux.h> 14*cb703792SJia Wang #include <linux/platform_device.h> 15*cb703792SJia Wang #include <linux/seq_file.h> 16*cb703792SJia Wang #include <linux/slab.h> 17*cb703792SJia Wang 18*cb703792SJia Wang #include "../core.h" 19*cb703792SJia Wang #include "../devicetree.h" 20*cb703792SJia Wang #include "../pinconf.h" 21*cb703792SJia Wang #include "../pinmux.h" 22*cb703792SJia Wang 23*cb703792SJia Wang #include "pinctrl-ultrarisc.h" 24*cb703792SJia Wang 25*cb703792SJia Wang #define UR_CONF_BIT_PER_PIN 4 26*cb703792SJia Wang #define UR_CONF_PIN_PER_REG (32 / UR_CONF_BIT_PER_PIN) 27*cb703792SJia Wang static const u32 ur_drive_strengths[] = { 20, 27, 33, 40 }; 28*cb703792SJia Wang 29*cb703792SJia Wang static const struct ur_port_desc *ur_get_pin_port(struct pinctrl_dev *pctldev, 30*cb703792SJia Wang unsigned int pin) 31*cb703792SJia Wang { 32*cb703792SJia Wang const struct pin_desc *desc = pin_desc_get(pctldev, pin); 33*cb703792SJia Wang 34*cb703792SJia Wang if (!desc || !desc->drv_data) 35*cb703792SJia Wang return NULL; 36*cb703792SJia Wang 37*cb703792SJia Wang return desc->drv_data; 38*cb703792SJia Wang } 39*cb703792SJia Wang 40*cb703792SJia Wang static u32 ur_get_pin_conf_offset(const struct ur_port_desc *port_desc, u32 pin) 41*cb703792SJia Wang { 42*cb703792SJia Wang return port_desc->conf_offset + 43*cb703792SJia Wang (pin / UR_CONF_PIN_PER_REG) * sizeof(u32); 44*cb703792SJia Wang } 45*cb703792SJia Wang 46*cb703792SJia Wang static int ur_read_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 *conf) 47*cb703792SJia Wang { 48*cb703792SJia Wang const struct ur_port_desc *port_desc; 49*cb703792SJia Wang u32 pin_offset; 50*cb703792SJia Wang u32 reg_offset; 51*cb703792SJia Wang u32 shift; 52*cb703792SJia Wang u32 mask; 53*cb703792SJia Wang 54*cb703792SJia Wang port_desc = ur_get_pin_port(pctrl->pctl_dev, pin); 55*cb703792SJia Wang if (!port_desc) 56*cb703792SJia Wang return -EINVAL; 57*cb703792SJia Wang 58*cb703792SJia Wang pin_offset = pin - port_desc->pin_base; 59*cb703792SJia Wang reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset); 60*cb703792SJia Wang shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN; 61*cb703792SJia Wang mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift; 62*cb703792SJia Wang *conf = field_get(mask, readl_relaxed(pctrl->base + reg_offset)); 63*cb703792SJia Wang 64*cb703792SJia Wang return 0; 65*cb703792SJia Wang } 66*cb703792SJia Wang 67*cb703792SJia Wang static int ur_write_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 conf) 68*cb703792SJia Wang { 69*cb703792SJia Wang const struct ur_port_desc *port_desc; 70*cb703792SJia Wang void __iomem *reg; 71*cb703792SJia Wang u32 pin_offset; 72*cb703792SJia Wang u32 reg_offset; 73*cb703792SJia Wang u32 shift; 74*cb703792SJia Wang u32 mask; 75*cb703792SJia Wang u32 val; 76*cb703792SJia Wang 77*cb703792SJia Wang port_desc = ur_get_pin_port(pctrl->pctl_dev, pin); 78*cb703792SJia Wang if (!port_desc) 79*cb703792SJia Wang return -EINVAL; 80*cb703792SJia Wang 81*cb703792SJia Wang pin_offset = pin - port_desc->pin_base; 82*cb703792SJia Wang reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset); 83*cb703792SJia Wang reg = pctrl->base + reg_offset; 84*cb703792SJia Wang shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN; 85*cb703792SJia Wang mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift; 86*cb703792SJia Wang 87*cb703792SJia Wang scoped_guard(raw_spinlock_irqsave, &pctrl->lock) { 88*cb703792SJia Wang val = readl_relaxed(reg); 89*cb703792SJia Wang val = (val & ~mask) | field_prep(mask, conf); 90*cb703792SJia Wang writel_relaxed(val, reg); 91*cb703792SJia Wang } 92*cb703792SJia Wang 93*cb703792SJia Wang return 0; 94*cb703792SJia Wang } 95*cb703792SJia Wang 96*cb703792SJia Wang static int ur_set_pin_mux(struct ur_pinctrl *pctrl, 97*cb703792SJia Wang const struct ur_port_desc *port_desc, 98*cb703792SJia Wang u32 pin_offset, u32 mode) 99*cb703792SJia Wang { 100*cb703792SJia Wang void __iomem *reg = pctrl->base + port_desc->func_offset; 101*cb703792SJia Wang u32 val; 102*cb703792SJia Wang 103*cb703792SJia Wang if (WARN_ON(pin_offset >= UR_MAX_PINS_PER_PORT)) 104*cb703792SJia Wang return -EINVAL; 105*cb703792SJia Wang 106*cb703792SJia Wang scoped_guard(raw_spinlock_irqsave, &pctrl->lock) { 107*cb703792SJia Wang val = readl_relaxed(reg); 108*cb703792SJia Wang val &= ~((UR_FUNC_0 | UR_FUNC_1) << pin_offset); 109*cb703792SJia Wang val |= mode << pin_offset; 110*cb703792SJia Wang writel_relaxed(val, reg); 111*cb703792SJia Wang } 112*cb703792SJia Wang 113*cb703792SJia Wang return 0; 114*cb703792SJia Wang } 115*cb703792SJia Wang 116*cb703792SJia Wang static int ur_set_pin_mux_by_num(struct ur_pinctrl *pctrl, unsigned int pin, u32 mode) 117*cb703792SJia Wang { 118*cb703792SJia Wang const struct ur_port_desc *port_desc = ur_get_pin_port(pctrl->pctl_dev, pin); 119*cb703792SJia Wang u32 pin_offset; 120*cb703792SJia Wang 121*cb703792SJia Wang if (!port_desc) 122*cb703792SJia Wang return -EINVAL; 123*cb703792SJia Wang 124*cb703792SJia Wang if (mode != UR_FUNC_DEFAULT && !(port_desc->supported_modes & mode)) 125*cb703792SJia Wang return -EINVAL; 126*cb703792SJia Wang 127*cb703792SJia Wang pin_offset = pin - port_desc->pin_base; 128*cb703792SJia Wang 129*cb703792SJia Wang return ur_set_pin_mux(pctrl, port_desc, pin_offset, mode); 130*cb703792SJia Wang } 131*cb703792SJia Wang 132*cb703792SJia Wang static int ur_hw_to_config(unsigned long *config, u32 conf) 133*cb703792SJia Wang { 134*cb703792SJia Wang enum pin_config_param param = pinconf_to_config_param(*config); 135*cb703792SJia Wang u32 drive = FIELD_GET(UR_DRIVE_MASK, conf); 136*cb703792SJia Wang u32 pull = FIELD_GET(UR_PULL_MASK, conf); 137*cb703792SJia Wang 138*cb703792SJia Wang switch (param) { 139*cb703792SJia Wang case PIN_CONFIG_BIAS_DISABLE: 140*cb703792SJia Wang case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 141*cb703792SJia Wang if (pull != UR_PULL_DIS) 142*cb703792SJia Wang return -EINVAL; 143*cb703792SJia Wang *config = pinconf_to_config_packed(param, 1); 144*cb703792SJia Wang return 0; 145*cb703792SJia Wang case PIN_CONFIG_BIAS_PULL_UP: 146*cb703792SJia Wang if (pull != UR_PULL_UP) 147*cb703792SJia Wang return -EINVAL; 148*cb703792SJia Wang *config = pinconf_to_config_packed(param, 1); 149*cb703792SJia Wang return 0; 150*cb703792SJia Wang case PIN_CONFIG_BIAS_PULL_DOWN: 151*cb703792SJia Wang case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: 152*cb703792SJia Wang if (pull != UR_PULL_DOWN) 153*cb703792SJia Wang return -EINVAL; 154*cb703792SJia Wang *config = pinconf_to_config_packed(param, 1); 155*cb703792SJia Wang return 0; 156*cb703792SJia Wang case PIN_CONFIG_DRIVE_STRENGTH: 157*cb703792SJia Wang if (drive >= ARRAY_SIZE(ur_drive_strengths)) 158*cb703792SJia Wang return -EINVAL; 159*cb703792SJia Wang *config = pinconf_to_config_packed(param, ur_drive_strengths[drive]); 160*cb703792SJia Wang return 0; 161*cb703792SJia Wang default: 162*cb703792SJia Wang return -EINVAL; 163*cb703792SJia Wang } 164*cb703792SJia Wang } 165*cb703792SJia Wang 166*cb703792SJia Wang static int ur_config_to_hw(unsigned long config, u32 *conf) 167*cb703792SJia Wang { 168*cb703792SJia Wang enum pin_config_param param = pinconf_to_config_param(config); 169*cb703792SJia Wang u32 arg = pinconf_to_config_argument(config); 170*cb703792SJia Wang 171*cb703792SJia Wang switch (param) { 172*cb703792SJia Wang case PIN_CONFIG_BIAS_DISABLE: 173*cb703792SJia Wang case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 174*cb703792SJia Wang FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DIS); 175*cb703792SJia Wang return 0; 176*cb703792SJia Wang case PIN_CONFIG_BIAS_PULL_UP: 177*cb703792SJia Wang FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_UP); 178*cb703792SJia Wang return 0; 179*cb703792SJia Wang case PIN_CONFIG_BIAS_PULL_DOWN: 180*cb703792SJia Wang case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: 181*cb703792SJia Wang FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DOWN); 182*cb703792SJia Wang return 0; 183*cb703792SJia Wang case PIN_CONFIG_DRIVE_STRENGTH: 184*cb703792SJia Wang for (u32 i = 0; i < ARRAY_SIZE(ur_drive_strengths); i++) { 185*cb703792SJia Wang if (ur_drive_strengths[i] != arg) 186*cb703792SJia Wang continue; 187*cb703792SJia Wang FIELD_MODIFY(UR_DRIVE_MASK, conf, i); 188*cb703792SJia Wang return 0; 189*cb703792SJia Wang } 190*cb703792SJia Wang return -EINVAL; 191*cb703792SJia Wang case PIN_CONFIG_PERSIST_STATE: 192*cb703792SJia Wang /* 193*cb703792SJia Wang * For PIN_CONFIG_PERSIST_STATE, gpiolib only treats 194*cb703792SJia Wang * -ENOTSUPP as an optional unsupported result. 195*cb703792SJia Wang * Do not use -EOPNOTSUPP here. 196*cb703792SJia Wang */ 197*cb703792SJia Wang return -ENOTSUPP; 198*cb703792SJia Wang default: 199*cb703792SJia Wang return -EOPNOTSUPP; 200*cb703792SJia Wang } 201*cb703792SJia Wang } 202*cb703792SJia Wang 203*cb703792SJia Wang /** 204*cb703792SJia Wang * ur_find_group_route() - Find the route matching a function and pin set 205*cb703792SJia Wang * @pctrl: pin controller instance 206*cb703792SJia Wang * @function: mux function name 207*cb703792SJia Wang * @group_mask: bitmap of pins in the selected group 208*cb703792SJia Wang * @route_out: returned route entry on success 209*cb703792SJia Wang * 210*cb703792SJia Wang * A mux function may be associated with multiple hardware routing options, 211*cb703792SJia Wang * each valid for a specific set of pins. This helper finds the unique route 212*cb703792SJia Wang * whose valid_pins mask covers all pins in @group_mask. 213*cb703792SJia Wang * 214*cb703792SJia Wang * The routing table must guarantee that a given function plus pin set 215*cb703792SJia Wang * resolves to exactly one route. If multiple routes match, the routing 216*cb703792SJia Wang * description is considered ambiguous and the lookup fails. 217*cb703792SJia Wang * 218*cb703792SJia Wang * Return: 0 on success, or -EINVAL if no matching route exists or if the 219*cb703792SJia Wang * routing table contains ambiguous entries. 220*cb703792SJia Wang */ 221*cb703792SJia Wang static int ur_find_group_route(struct ur_pinctrl *pctrl, 222*cb703792SJia Wang const char *function, 223*cb703792SJia Wang u64 group_mask, 224*cb703792SJia Wang const struct ur_func_route **route_out) 225*cb703792SJia Wang { 226*cb703792SJia Wang const struct ur_func_route *match = NULL; 227*cb703792SJia Wang 228*cb703792SJia Wang for (u32 i = 0; i < pctrl->data->num_routes; i++) { 229*cb703792SJia Wang const struct ur_func_route *route = &pctrl->data->routes[i]; 230*cb703792SJia Wang 231*cb703792SJia Wang if (strcmp(route->function, function)) 232*cb703792SJia Wang continue; 233*cb703792SJia Wang 234*cb703792SJia Wang if ((route->valid_pins & group_mask) != group_mask) 235*cb703792SJia Wang continue; 236*cb703792SJia Wang 237*cb703792SJia Wang if (match) { 238*cb703792SJia Wang dev_err(pctrl->dev, 239*cb703792SJia Wang "ambiguous route for function %s group_mask=%#llx\n", 240*cb703792SJia Wang function, (unsigned long long)group_mask); 241*cb703792SJia Wang return -EINVAL; 242*cb703792SJia Wang } 243*cb703792SJia Wang 244*cb703792SJia Wang match = route; 245*cb703792SJia Wang } 246*cb703792SJia Wang 247*cb703792SJia Wang if (match) { 248*cb703792SJia Wang *route_out = match; 249*cb703792SJia Wang return 0; 250*cb703792SJia Wang } 251*cb703792SJia Wang 252*cb703792SJia Wang return -EINVAL; 253*cb703792SJia Wang } 254*cb703792SJia Wang 255*cb703792SJia Wang static const char *ur_get_group_function(struct pinctrl_dev *pctldev, 256*cb703792SJia Wang unsigned int group_selector, 257*cb703792SJia Wang unsigned int pin_index) 258*cb703792SJia Wang { 259*cb703792SJia Wang const struct group_desc *group; 260*cb703792SJia Wang const char * const *functions; 261*cb703792SJia Wang 262*cb703792SJia Wang group = pinctrl_generic_get_group(pctldev, group_selector); 263*cb703792SJia Wang if (!group || pin_index >= group->grp.npins || !group->data) 264*cb703792SJia Wang return NULL; 265*cb703792SJia Wang 266*cb703792SJia Wang functions = group->data; 267*cb703792SJia Wang 268*cb703792SJia Wang return functions[pin_index]; 269*cb703792SJia Wang } 270*cb703792SJia Wang 271*cb703792SJia Wang static int ur_resolve_group_mux(struct pinctrl_dev *pctldev, 272*cb703792SJia Wang struct ur_pinctrl *pctrl, 273*cb703792SJia Wang unsigned int group_selector, 274*cb703792SJia Wang const unsigned int *pins, 275*cb703792SJia Wang unsigned int npins, 276*cb703792SJia Wang const struct ur_func_route **route_out) 277*cb703792SJia Wang { 278*cb703792SJia Wang const char *function; 279*cb703792SJia Wang u64 group_mask = 0; 280*cb703792SJia Wang 281*cb703792SJia Wang if (!npins) 282*cb703792SJia Wang return -EINVAL; 283*cb703792SJia Wang 284*cb703792SJia Wang function = ur_get_group_function(pctldev, group_selector, 0); 285*cb703792SJia Wang if (!function) 286*cb703792SJia Wang return -EINVAL; 287*cb703792SJia Wang 288*cb703792SJia Wang for (u32 i = 0; i < npins; i++) 289*cb703792SJia Wang group_mask |= BIT_ULL(pins[i]); 290*cb703792SJia Wang 291*cb703792SJia Wang return ur_find_group_route(pctrl, function, group_mask, route_out); 292*cb703792SJia Wang } 293*cb703792SJia Wang 294*cb703792SJia Wang static bool ur_function_is_gpio(struct pinctrl_dev *pctldev, 295*cb703792SJia Wang unsigned int selector) 296*cb703792SJia Wang { 297*cb703792SJia Wang const struct function_desc *function; 298*cb703792SJia Wang 299*cb703792SJia Wang function = pinmux_generic_get_function(pctldev, selector); 300*cb703792SJia Wang if (!function) 301*cb703792SJia Wang return false; 302*cb703792SJia Wang 303*cb703792SJia Wang for (u32 i = 0; i < function->func->ngroups; i++) { 304*cb703792SJia Wang const char *func_name; 305*cb703792SJia Wang int group_selector; 306*cb703792SJia Wang 307*cb703792SJia Wang group_selector = pinctrl_get_group_selector(pctldev, 308*cb703792SJia Wang function->func->groups[i]); 309*cb703792SJia Wang if (group_selector < 0) 310*cb703792SJia Wang return false; 311*cb703792SJia Wang 312*cb703792SJia Wang func_name = ur_get_group_function(pctldev, group_selector, 0); 313*cb703792SJia Wang if (!func_name || strcmp(func_name, "gpio")) 314*cb703792SJia Wang return false; 315*cb703792SJia Wang } 316*cb703792SJia Wang 317*cb703792SJia Wang return true; 318*cb703792SJia Wang } 319*cb703792SJia Wang 320*cb703792SJia Wang static const struct pinctrl_ops ur_pinctrl_ops = { 321*cb703792SJia Wang .get_groups_count = pinctrl_generic_get_group_count, 322*cb703792SJia Wang .get_group_name = pinctrl_generic_get_group_name, 323*cb703792SJia Wang .get_group_pins = pinctrl_generic_get_group_pins, 324*cb703792SJia Wang .dt_node_to_map = pinctrl_generic_pins_function_dt_node_to_map, 325*cb703792SJia Wang .dt_free_map = pinconf_generic_dt_free_map, 326*cb703792SJia Wang }; 327*cb703792SJia Wang 328*cb703792SJia Wang static int ur_gpio_request_enable(struct pinctrl_dev *pctldev, 329*cb703792SJia Wang struct pinctrl_gpio_range *range, 330*cb703792SJia Wang unsigned int offset) 331*cb703792SJia Wang { 332*cb703792SJia Wang struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 333*cb703792SJia Wang const struct ur_port_desc *port_desc; 334*cb703792SJia Wang const struct ur_func_route *route; 335*cb703792SJia Wang int ret; 336*cb703792SJia Wang 337*cb703792SJia Wang (void)range; 338*cb703792SJia Wang 339*cb703792SJia Wang port_desc = ur_get_pin_port(pctldev, offset); 340*cb703792SJia Wang if (!port_desc || !port_desc->supports_gpio) 341*cb703792SJia Wang return -EINVAL; 342*cb703792SJia Wang 343*cb703792SJia Wang ret = ur_find_group_route(pctrl, "gpio", BIT_ULL(offset), &route); 344*cb703792SJia Wang if (ret) 345*cb703792SJia Wang return ret; 346*cb703792SJia Wang 347*cb703792SJia Wang return ur_set_pin_mux_by_num(pctrl, offset, route->mode); 348*cb703792SJia Wang } 349*cb703792SJia Wang 350*cb703792SJia Wang static int ur_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, 351*cb703792SJia Wang unsigned int group_selector) 352*cb703792SJia Wang { 353*cb703792SJia Wang struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 354*cb703792SJia Wang const struct ur_func_route *route; 355*cb703792SJia Wang const unsigned int *pins; 356*cb703792SJia Wang unsigned int npins; 357*cb703792SJia Wang int ret; 358*cb703792SJia Wang 359*cb703792SJia Wang (void)func_selector; 360*cb703792SJia Wang 361*cb703792SJia Wang ret = pinctrl_generic_get_group_pins(pctldev, group_selector, &pins, &npins); 362*cb703792SJia Wang if (ret) 363*cb703792SJia Wang return ret; 364*cb703792SJia Wang 365*cb703792SJia Wang ret = ur_resolve_group_mux(pctldev, pctrl, group_selector, pins, npins, 366*cb703792SJia Wang &route); 367*cb703792SJia Wang if (ret) 368*cb703792SJia Wang return ret; 369*cb703792SJia Wang 370*cb703792SJia Wang for (u32 i = 0; i < npins; i++) { 371*cb703792SJia Wang ret = ur_set_pin_mux_by_num(pctrl, pins[i], route->mode); 372*cb703792SJia Wang if (ret) 373*cb703792SJia Wang return ret; 374*cb703792SJia Wang } 375*cb703792SJia Wang 376*cb703792SJia Wang return 0; 377*cb703792SJia Wang } 378*cb703792SJia Wang 379*cb703792SJia Wang static const struct pinmux_ops ur_pinmux_ops = { 380*cb703792SJia Wang .get_functions_count = pinmux_generic_get_function_count, 381*cb703792SJia Wang .get_function_name = pinmux_generic_get_function_name, 382*cb703792SJia Wang .get_function_groups = pinmux_generic_get_function_groups, 383*cb703792SJia Wang .function_is_gpio = ur_function_is_gpio, 384*cb703792SJia Wang .set_mux = ur_set_mux, 385*cb703792SJia Wang .gpio_request_enable = ur_gpio_request_enable, 386*cb703792SJia Wang .strict = true, 387*cb703792SJia Wang }; 388*cb703792SJia Wang 389*cb703792SJia Wang static int ur_pin_config_get(struct pinctrl_dev *pctldev, 390*cb703792SJia Wang unsigned int pin, 391*cb703792SJia Wang unsigned long *config) 392*cb703792SJia Wang { 393*cb703792SJia Wang struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 394*cb703792SJia Wang u32 conf; 395*cb703792SJia Wang int ret; 396*cb703792SJia Wang 397*cb703792SJia Wang ret = ur_read_pin_conf(pctrl, pin, &conf); 398*cb703792SJia Wang if (ret) 399*cb703792SJia Wang return ret; 400*cb703792SJia Wang 401*cb703792SJia Wang return ur_hw_to_config(config, conf); 402*cb703792SJia Wang } 403*cb703792SJia Wang 404*cb703792SJia Wang static int ur_pin_config_set(struct pinctrl_dev *pctldev, 405*cb703792SJia Wang unsigned int pin, 406*cb703792SJia Wang unsigned long *configs, 407*cb703792SJia Wang unsigned int num_configs) 408*cb703792SJia Wang { 409*cb703792SJia Wang struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 410*cb703792SJia Wang u32 conf; 411*cb703792SJia Wang int ret; 412*cb703792SJia Wang 413*cb703792SJia Wang ret = ur_read_pin_conf(pctrl, pin, &conf); 414*cb703792SJia Wang if (ret) 415*cb703792SJia Wang return ret; 416*cb703792SJia Wang 417*cb703792SJia Wang for (u32 i = 0; i < num_configs; i++) { 418*cb703792SJia Wang ret = ur_config_to_hw(configs[i], &conf); 419*cb703792SJia Wang if (ret) 420*cb703792SJia Wang return ret; 421*cb703792SJia Wang } 422*cb703792SJia Wang 423*cb703792SJia Wang return ur_write_pin_conf(pctrl, pin, conf); 424*cb703792SJia Wang } 425*cb703792SJia Wang 426*cb703792SJia Wang static int ur_pin_config_group_get(struct pinctrl_dev *pctldev, 427*cb703792SJia Wang unsigned int selector, 428*cb703792SJia Wang unsigned long *config) 429*cb703792SJia Wang { 430*cb703792SJia Wang const unsigned int *pins; 431*cb703792SJia Wang unsigned int npins; 432*cb703792SJia Wang int ret; 433*cb703792SJia Wang 434*cb703792SJia Wang ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins); 435*cb703792SJia Wang if (ret || !npins) 436*cb703792SJia Wang return ret ?: -EINVAL; 437*cb703792SJia Wang 438*cb703792SJia Wang return ur_pin_config_get(pctldev, pins[0], config); 439*cb703792SJia Wang } 440*cb703792SJia Wang 441*cb703792SJia Wang static int ur_pin_config_group_set(struct pinctrl_dev *pctldev, 442*cb703792SJia Wang unsigned int selector, 443*cb703792SJia Wang unsigned long *configs, 444*cb703792SJia Wang unsigned int num_configs) 445*cb703792SJia Wang { 446*cb703792SJia Wang const unsigned int *pins; 447*cb703792SJia Wang unsigned int npins; 448*cb703792SJia Wang int ret; 449*cb703792SJia Wang 450*cb703792SJia Wang ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins); 451*cb703792SJia Wang if (ret) 452*cb703792SJia Wang return ret; 453*cb703792SJia Wang 454*cb703792SJia Wang for (u32 i = 0; i < npins; i++) { 455*cb703792SJia Wang ret = ur_pin_config_set(pctldev, pins[i], configs, num_configs); 456*cb703792SJia Wang if (ret) 457*cb703792SJia Wang return ret; 458*cb703792SJia Wang } 459*cb703792SJia Wang 460*cb703792SJia Wang return 0; 461*cb703792SJia Wang } 462*cb703792SJia Wang 463*cb703792SJia Wang static const struct pinconf_ops ur_pinconf_ops = { 464*cb703792SJia Wang .pin_config_get = ur_pin_config_get, 465*cb703792SJia Wang .pin_config_set = ur_pin_config_set, 466*cb703792SJia Wang .pin_config_group_get = ur_pin_config_group_get, 467*cb703792SJia Wang .pin_config_group_set = ur_pin_config_group_set, 468*cb703792SJia Wang .is_generic = true, 469*cb703792SJia Wang .pin_config_config_dbg_show = pinconf_generic_dump_config, 470*cb703792SJia Wang }; 471*cb703792SJia Wang 472*cb703792SJia Wang int ur_pinctrl_probe(struct platform_device *pdev, 473*cb703792SJia Wang const struct ur_pinctrl_data *data) 474*cb703792SJia Wang { 475*cb703792SJia Wang struct pinctrl_desc *desc; 476*cb703792SJia Wang struct ur_pinctrl *pctrl; 477*cb703792SJia Wang int ret; 478*cb703792SJia Wang 479*cb703792SJia Wang if (!data) 480*cb703792SJia Wang return -ENODEV; 481*cb703792SJia Wang 482*cb703792SJia Wang desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL); 483*cb703792SJia Wang if (!desc) 484*cb703792SJia Wang return -ENOMEM; 485*cb703792SJia Wang 486*cb703792SJia Wang pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); 487*cb703792SJia Wang if (!pctrl) 488*cb703792SJia Wang return -ENOMEM; 489*cb703792SJia Wang 490*cb703792SJia Wang pctrl->base = devm_platform_ioremap_resource(pdev, 0); 491*cb703792SJia Wang if (IS_ERR(pctrl->base)) 492*cb703792SJia Wang return PTR_ERR(pctrl->base); 493*cb703792SJia Wang pctrl->dev = &pdev->dev; 494*cb703792SJia Wang pctrl->data = data; 495*cb703792SJia Wang 496*cb703792SJia Wang raw_spin_lock_init(&pctrl->lock); 497*cb703792SJia Wang 498*cb703792SJia Wang desc->name = dev_name(&pdev->dev); 499*cb703792SJia Wang desc->owner = THIS_MODULE; 500*cb703792SJia Wang desc->pins = data->pins; 501*cb703792SJia Wang desc->npins = data->npins; 502*cb703792SJia Wang desc->pctlops = &ur_pinctrl_ops; 503*cb703792SJia Wang desc->pmxops = &ur_pinmux_ops; 504*cb703792SJia Wang desc->confops = &ur_pinconf_ops; 505*cb703792SJia Wang 506*cb703792SJia Wang ret = devm_pinctrl_register_and_init(&pdev->dev, desc, pctrl, &pctrl->pctl_dev); 507*cb703792SJia Wang if (ret) 508*cb703792SJia Wang return dev_err_probe(&pdev->dev, ret, "failed to register pinctrl\n"); 509*cb703792SJia Wang 510*cb703792SJia Wang platform_set_drvdata(pdev, pctrl); 511*cb703792SJia Wang 512*cb703792SJia Wang return pinctrl_enable(pctrl->pctl_dev); 513*cb703792SJia Wang } 514*cb703792SJia Wang EXPORT_SYMBOL_GPL(ur_pinctrl_probe); 515*cb703792SJia Wang 516*cb703792SJia Wang MODULE_DESCRIPTION("UltraRISC pinctrl core driver"); 517*cb703792SJia Wang MODULE_LICENSE("GPL"); 518