1/* 2 * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15#include <linux/export.h> 16#include <linux/mfd/syscon.h> 17#include <linux/pinctrl/pinconf.h> 18#include <linux/pinctrl/pinconf-generic.h> 19#include <linux/pinctrl/pinctrl.h> 20#include <linux/pinctrl/pinmux.h> 21#include <linux/platform_device.h> 22#include <linux/regmap.h> 23 24#include "../core.h" 25#include "../pinctrl-utils.h" 26#include "pinctrl-uniphier.h" 27 28struct uniphier_pinctrl_priv { 29 struct pinctrl_dev *pctldev; 30 struct regmap *regmap; 31 struct uniphier_pinctrl_socdata *socdata; 32}; 33 34static int uniphier_pctl_get_groups_count(struct pinctrl_dev *pctldev) 35{ 36 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 37 38 return priv->socdata->groups_count; 39} 40 41static const char *uniphier_pctl_get_group_name(struct pinctrl_dev *pctldev, 42 unsigned selector) 43{ 44 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 45 46 return priv->socdata->groups[selector].name; 47} 48 49static int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev, 50 unsigned selector, 51 const unsigned **pins, 52 unsigned *num_pins) 53{ 54 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 55 56 *pins = priv->socdata->groups[selector].pins; 57 *num_pins = priv->socdata->groups[selector].num_pins; 58 59 return 0; 60} 61 62#ifdef CONFIG_DEBUG_FS 63static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, 64 struct seq_file *s, unsigned offset) 65{ 66 const struct pinctrl_pin_desc *pin = &pctldev->desc->pins[offset]; 67 const char *pull_dir, *drv_str; 68 69 switch (uniphier_pin_get_pull_dir(pin->drv_data)) { 70 case UNIPHIER_PIN_PULL_UP: 71 pull_dir = "UP"; 72 break; 73 case UNIPHIER_PIN_PULL_DOWN: 74 pull_dir = "DOWN"; 75 break; 76 case UNIPHIER_PIN_PULL_NONE: 77 pull_dir = "NONE"; 78 break; 79 default: 80 BUG(); 81 } 82 83 switch (uniphier_pin_get_drv_str(pin->drv_data)) { 84 case UNIPHIER_PIN_DRV_4_8: 85 drv_str = "4/8(mA)"; 86 break; 87 case UNIPHIER_PIN_DRV_8_12_16_20: 88 drv_str = "8/12/16/20(mA)"; 89 break; 90 case UNIPHIER_PIN_DRV_FIXED_4: 91 drv_str = "4(mA)"; 92 break; 93 case UNIPHIER_PIN_DRV_FIXED_5: 94 drv_str = "5(mA)"; 95 break; 96 case UNIPHIER_PIN_DRV_FIXED_8: 97 drv_str = "8(mA)"; 98 break; 99 case UNIPHIER_PIN_DRV_NONE: 100 drv_str = "NONE"; 101 break; 102 default: 103 BUG(); 104 } 105 106 seq_printf(s, " PULL_DIR=%s DRV_STR=%s", pull_dir, drv_str); 107} 108#endif 109 110static const struct pinctrl_ops uniphier_pctlops = { 111 .get_groups_count = uniphier_pctl_get_groups_count, 112 .get_group_name = uniphier_pctl_get_group_name, 113 .get_group_pins = uniphier_pctl_get_group_pins, 114#ifdef CONFIG_DEBUG_FS 115 .pin_dbg_show = uniphier_pctl_pin_dbg_show, 116#endif 117 .dt_node_to_map = pinconf_generic_dt_node_to_map_all, 118 .dt_free_map = pinctrl_utils_dt_free_map, 119}; 120 121static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, 122 const struct pinctrl_pin_desc *pin, 123 enum pin_config_param param) 124{ 125 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 126 enum uniphier_pin_pull_dir pull_dir = 127 uniphier_pin_get_pull_dir(pin->drv_data); 128 unsigned int pupdctrl, reg, shift, val; 129 unsigned int expected = 1; 130 int ret; 131 132 switch (param) { 133 case PIN_CONFIG_BIAS_DISABLE: 134 if (pull_dir == UNIPHIER_PIN_PULL_NONE) 135 return 0; 136 if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || 137 pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) 138 return -EINVAL; 139 expected = 0; 140 break; 141 case PIN_CONFIG_BIAS_PULL_UP: 142 if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED) 143 return 0; 144 if (pull_dir != UNIPHIER_PIN_PULL_UP) 145 return -EINVAL; 146 break; 147 case PIN_CONFIG_BIAS_PULL_DOWN: 148 if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) 149 return 0; 150 if (pull_dir != UNIPHIER_PIN_PULL_DOWN) 151 return -EINVAL; 152 break; 153 default: 154 BUG(); 155 } 156 157 pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data); 158 159 reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; 160 shift = pupdctrl % 32; 161 162 ret = regmap_read(priv->regmap, reg, &val); 163 if (ret) 164 return ret; 165 166 val = (val >> shift) & 1; 167 168 return (val == expected) ? 0 : -EINVAL; 169} 170 171static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, 172 const struct pinctrl_pin_desc *pin, 173 u16 *strength) 174{ 175 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 176 enum uniphier_pin_drv_str drv_str = 177 uniphier_pin_get_drv_str(pin->drv_data); 178 const unsigned int strength_4_8[] = {4, 8}; 179 const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20}; 180 const unsigned int *supported_strength; 181 unsigned int drvctrl, reg, shift, mask, width, val; 182 int ret; 183 184 switch (drv_str) { 185 case UNIPHIER_PIN_DRV_4_8: 186 supported_strength = strength_4_8; 187 width = 1; 188 break; 189 case UNIPHIER_PIN_DRV_8_12_16_20: 190 supported_strength = strength_8_12_16_20; 191 width = 2; 192 break; 193 case UNIPHIER_PIN_DRV_FIXED_4: 194 *strength = 4; 195 return 0; 196 case UNIPHIER_PIN_DRV_FIXED_5: 197 *strength = 5; 198 return 0; 199 case UNIPHIER_PIN_DRV_FIXED_8: 200 *strength = 8; 201 return 0; 202 default: 203 /* drive strength control is not supported for this pin */ 204 return -EINVAL; 205 } 206 207 drvctrl = uniphier_pin_get_drvctrl(pin->drv_data); 208 drvctrl *= width; 209 210 reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE : 211 UNIPHIER_PINCTRL_DRVCTRL_BASE; 212 213 reg += drvctrl / 32 * 4; 214 shift = drvctrl % 32; 215 mask = (1U << width) - 1; 216 217 ret = regmap_read(priv->regmap, reg, &val); 218 if (ret) 219 return ret; 220 221 *strength = supported_strength[(val >> shift) & mask]; 222 223 return 0; 224} 225 226static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev, 227 const struct pinctrl_pin_desc *pin) 228{ 229 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 230 unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data); 231 unsigned int val; 232 int ret; 233 234 if (iectrl == UNIPHIER_PIN_IECTRL_NONE) 235 /* This pin is always input-enabled. */ 236 return 0; 237 238 ret = regmap_read(priv->regmap, UNIPHIER_PINCTRL_IECTRL, &val); 239 if (ret) 240 return ret; 241 242 return val & BIT(iectrl) ? 0 : -EINVAL; 243} 244 245static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev, 246 unsigned pin, 247 unsigned long *configs) 248{ 249 const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin]; 250 enum pin_config_param param = pinconf_to_config_param(*configs); 251 bool has_arg = false; 252 u16 arg; 253 int ret; 254 255 switch (param) { 256 case PIN_CONFIG_BIAS_DISABLE: 257 case PIN_CONFIG_BIAS_PULL_UP: 258 case PIN_CONFIG_BIAS_PULL_DOWN: 259 ret = uniphier_conf_pin_bias_get(pctldev, pin_desc, param); 260 break; 261 case PIN_CONFIG_DRIVE_STRENGTH: 262 ret = uniphier_conf_pin_drive_get(pctldev, pin_desc, &arg); 263 has_arg = true; 264 break; 265 case PIN_CONFIG_INPUT_ENABLE: 266 ret = uniphier_conf_pin_input_enable_get(pctldev, pin_desc); 267 break; 268 default: 269 /* unsupported parameter */ 270 ret = -EINVAL; 271 break; 272 } 273 274 if (ret == 0 && has_arg) 275 *configs = pinconf_to_config_packed(param, arg); 276 277 return ret; 278} 279 280static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, 281 const struct pinctrl_pin_desc *pin, 282 enum pin_config_param param, 283 u16 arg) 284{ 285 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 286 enum uniphier_pin_pull_dir pull_dir = 287 uniphier_pin_get_pull_dir(pin->drv_data); 288 unsigned int pupdctrl, reg, shift; 289 unsigned int val = 1; 290 291 switch (param) { 292 case PIN_CONFIG_BIAS_DISABLE: 293 if (pull_dir == UNIPHIER_PIN_PULL_NONE) 294 return 0; 295 if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || 296 pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) { 297 dev_err(pctldev->dev, 298 "can not disable pull register for pin %u (%s)\n", 299 pin->number, pin->name); 300 return -EINVAL; 301 } 302 val = 0; 303 break; 304 case PIN_CONFIG_BIAS_PULL_UP: 305 if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED && arg != 0) 306 return 0; 307 if (pull_dir != UNIPHIER_PIN_PULL_UP) { 308 dev_err(pctldev->dev, 309 "pull-up is unsupported for pin %u (%s)\n", 310 pin->number, pin->name); 311 return -EINVAL; 312 } 313 if (arg == 0) { 314 dev_err(pctldev->dev, "pull-up can not be total\n"); 315 return -EINVAL; 316 } 317 break; 318 case PIN_CONFIG_BIAS_PULL_DOWN: 319 if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED && arg != 0) 320 return 0; 321 if (pull_dir != UNIPHIER_PIN_PULL_DOWN) { 322 dev_err(pctldev->dev, 323 "pull-down is unsupported for pin %u (%s)\n", 324 pin->number, pin->name); 325 return -EINVAL; 326 } 327 if (arg == 0) { 328 dev_err(pctldev->dev, "pull-down can not be total\n"); 329 return -EINVAL; 330 } 331 break; 332 case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: 333 if (pull_dir == UNIPHIER_PIN_PULL_NONE) { 334 dev_err(pctldev->dev, 335 "pull-up/down is unsupported for pin %u (%s)\n", 336 pin->number, pin->name); 337 return -EINVAL; 338 } 339 340 if (arg == 0) 341 return 0; /* configuration ingored */ 342 break; 343 default: 344 BUG(); 345 } 346 347 pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data); 348 349 reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; 350 shift = pupdctrl % 32; 351 352 return regmap_update_bits(priv->regmap, reg, 1 << shift, val << shift); 353} 354 355static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, 356 const struct pinctrl_pin_desc *pin, 357 u16 strength) 358{ 359 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 360 enum uniphier_pin_drv_str drv_str = 361 uniphier_pin_get_drv_str(pin->drv_data); 362 const unsigned int strength_4_8[] = {4, 8, -1}; 363 const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20, -1}; 364 const unsigned int *supported_strength; 365 unsigned int drvctrl, reg, shift, mask, width, val; 366 367 switch (drv_str) { 368 case UNIPHIER_PIN_DRV_4_8: 369 supported_strength = strength_4_8; 370 width = 1; 371 break; 372 case UNIPHIER_PIN_DRV_8_12_16_20: 373 supported_strength = strength_8_12_16_20; 374 width = 2; 375 break; 376 default: 377 dev_err(pctldev->dev, 378 "cannot change drive strength for pin %u (%s)\n", 379 pin->number, pin->name); 380 return -EINVAL; 381 } 382 383 for (val = 0; supported_strength[val] > 0; val++) { 384 if (supported_strength[val] > strength) 385 break; 386 } 387 388 if (val == 0) { 389 dev_err(pctldev->dev, 390 "unsupported drive strength %u mA for pin %u (%s)\n", 391 strength, pin->number, pin->name); 392 return -EINVAL; 393 } 394 395 val--; 396 397 drvctrl = uniphier_pin_get_drvctrl(pin->drv_data); 398 drvctrl *= width; 399 400 reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE : 401 UNIPHIER_PINCTRL_DRVCTRL_BASE; 402 403 reg += drvctrl / 32 * 4; 404 shift = drvctrl % 32; 405 mask = (1U << width) - 1; 406 407 return regmap_update_bits(priv->regmap, reg, 408 mask << shift, val << shift); 409} 410 411static int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev, 412 const struct pinctrl_pin_desc *pin, 413 u16 enable) 414{ 415 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 416 unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data); 417 418 if (enable == 0) { 419 /* 420 * Multiple pins share one input enable, so per-pin disabling 421 * is impossible. 422 */ 423 dev_err(pctldev->dev, "unable to disable input\n"); 424 return -EINVAL; 425 } 426 427 if (iectrl == UNIPHIER_PIN_IECTRL_NONE) 428 /* This pin is always input-enabled. nothing to do. */ 429 return 0; 430 431 return regmap_update_bits(priv->regmap, UNIPHIER_PINCTRL_IECTRL, 432 BIT(iectrl), BIT(iectrl)); 433} 434 435static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev, 436 unsigned pin, 437 unsigned long *configs, 438 unsigned num_configs) 439{ 440 const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin]; 441 int i, ret; 442 443 for (i = 0; i < num_configs; i++) { 444 enum pin_config_param param = 445 pinconf_to_config_param(configs[i]); 446 u16 arg = pinconf_to_config_argument(configs[i]); 447 448 switch (param) { 449 case PIN_CONFIG_BIAS_DISABLE: 450 case PIN_CONFIG_BIAS_PULL_UP: 451 case PIN_CONFIG_BIAS_PULL_DOWN: 452 case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: 453 ret = uniphier_conf_pin_bias_set(pctldev, pin_desc, 454 param, arg); 455 break; 456 case PIN_CONFIG_DRIVE_STRENGTH: 457 ret = uniphier_conf_pin_drive_set(pctldev, pin_desc, 458 arg); 459 break; 460 case PIN_CONFIG_INPUT_ENABLE: 461 ret = uniphier_conf_pin_input_enable(pctldev, 462 pin_desc, arg); 463 break; 464 default: 465 dev_err(pctldev->dev, 466 "unsupported configuration parameter %u\n", 467 param); 468 return -EINVAL; 469 } 470 471 if (ret) 472 return ret; 473 } 474 475 return 0; 476} 477 478static int uniphier_conf_pin_config_group_set(struct pinctrl_dev *pctldev, 479 unsigned selector, 480 unsigned long *configs, 481 unsigned num_configs) 482{ 483 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 484 const unsigned *pins = priv->socdata->groups[selector].pins; 485 unsigned num_pins = priv->socdata->groups[selector].num_pins; 486 int i, ret; 487 488 for (i = 0; i < num_pins; i++) { 489 ret = uniphier_conf_pin_config_set(pctldev, pins[i], 490 configs, num_configs); 491 if (ret) 492 return ret; 493 } 494 495 return 0; 496} 497 498static const struct pinconf_ops uniphier_confops = { 499 .is_generic = true, 500 .pin_config_get = uniphier_conf_pin_config_get, 501 .pin_config_set = uniphier_conf_pin_config_set, 502 .pin_config_group_set = uniphier_conf_pin_config_group_set, 503}; 504 505static int uniphier_pmx_get_functions_count(struct pinctrl_dev *pctldev) 506{ 507 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 508 509 return priv->socdata->functions_count; 510} 511 512static const char *uniphier_pmx_get_function_name(struct pinctrl_dev *pctldev, 513 unsigned selector) 514{ 515 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 516 517 return priv->socdata->functions[selector].name; 518} 519 520static int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev, 521 unsigned selector, 522 const char * const **groups, 523 unsigned *num_groups) 524{ 525 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 526 527 *groups = priv->socdata->functions[selector].groups; 528 *num_groups = priv->socdata->functions[selector].num_groups; 529 530 return 0; 531} 532 533static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin, 534 unsigned muxval) 535{ 536 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 537 unsigned mux_bits = priv->socdata->mux_bits; 538 unsigned reg_stride = priv->socdata->reg_stride; 539 unsigned reg, reg_end, shift, mask; 540 int ret; 541 542 /* some pins need input-enabling */ 543 ret = uniphier_conf_pin_input_enable(pctldev, 544 &pctldev->desc->pins[pin], 1); 545 if (ret) 546 return ret; 547 548 reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; 549 reg_end = reg + reg_stride; 550 shift = pin * mux_bits % 32; 551 mask = (1U << mux_bits) - 1; 552 553 /* 554 * If reg_stride is greater than 4, the MSB of each pinsel shall be 555 * stored in the offset+4. 556 */ 557 for (; reg < reg_end; reg += 4) { 558 ret = regmap_update_bits(priv->regmap, reg, 559 mask << shift, muxval << shift); 560 if (ret) 561 return ret; 562 muxval >>= mux_bits; 563 } 564 565 if (priv->socdata->load_pinctrl) { 566 ret = regmap_write(priv->regmap, 567 UNIPHIER_PINCTRL_LOAD_PINMUX, 1); 568 if (ret) 569 return ret; 570 } 571 572 return 0; 573} 574 575static int uniphier_pmx_set_mux(struct pinctrl_dev *pctldev, 576 unsigned func_selector, 577 unsigned group_selector) 578{ 579 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 580 const struct uniphier_pinctrl_group *grp = 581 &priv->socdata->groups[group_selector]; 582 int i; 583 int ret; 584 585 for (i = 0; i < grp->num_pins; i++) { 586 ret = uniphier_pmx_set_one_mux(pctldev, grp->pins[i], 587 grp->muxvals[i]); 588 if (ret) 589 return ret; 590 } 591 592 return 0; 593} 594 595static int uniphier_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, 596 struct pinctrl_gpio_range *range, 597 unsigned offset) 598{ 599 struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); 600 const struct uniphier_pinctrl_group *groups = priv->socdata->groups; 601 int groups_count = priv->socdata->groups_count; 602 enum uniphier_pinmux_gpio_range_type range_type; 603 int i, j; 604 605 if (strstr(range->name, "irq")) 606 range_type = UNIPHIER_PINMUX_GPIO_RANGE_IRQ; 607 else 608 range_type = UNIPHIER_PINMUX_GPIO_RANGE_PORT; 609 610 for (i = 0; i < groups_count; i++) { 611 if (groups[i].range_type != range_type) 612 continue; 613 614 for (j = 0; j < groups[i].num_pins; j++) 615 if (groups[i].pins[j] == offset) 616 goto found; 617 } 618 619 dev_err(pctldev->dev, "pin %u does not support GPIO\n", offset); 620 return -EINVAL; 621 622found: 623 return uniphier_pmx_set_one_mux(pctldev, offset, groups[i].muxvals[j]); 624} 625 626static const struct pinmux_ops uniphier_pmxops = { 627 .get_functions_count = uniphier_pmx_get_functions_count, 628 .get_function_name = uniphier_pmx_get_function_name, 629 .get_function_groups = uniphier_pmx_get_function_groups, 630 .set_mux = uniphier_pmx_set_mux, 631 .gpio_request_enable = uniphier_pmx_gpio_request_enable, 632 .strict = true, 633}; 634 635int uniphier_pinctrl_probe(struct platform_device *pdev, 636 struct pinctrl_desc *desc, 637 struct uniphier_pinctrl_socdata *socdata) 638{ 639 struct device *dev = &pdev->dev; 640 struct uniphier_pinctrl_priv *priv; 641 642 if (!socdata || 643 !socdata->groups || 644 !socdata->groups_count || 645 !socdata->functions || 646 !socdata->functions_count || 647 !socdata->mux_bits || 648 !socdata->reg_stride) { 649 dev_err(dev, "pinctrl socdata lacks necessary members\n"); 650 return -EINVAL; 651 } 652 653 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 654 if (!priv) 655 return -ENOMEM; 656 657 priv->regmap = syscon_node_to_regmap(dev->of_node); 658 if (IS_ERR(priv->regmap)) { 659 dev_err(dev, "failed to get regmap\n"); 660 return PTR_ERR(priv->regmap); 661 } 662 663 priv->socdata = socdata; 664 desc->pctlops = &uniphier_pctlops; 665 desc->pmxops = &uniphier_pmxops; 666 desc->confops = &uniphier_confops; 667 668 priv->pctldev = pinctrl_register(desc, dev, priv); 669 if (IS_ERR(priv->pctldev)) { 670 dev_err(dev, "failed to register UniPhier pinctrl driver\n"); 671 return PTR_ERR(priv->pctldev); 672 } 673 674 platform_set_drvdata(pdev, priv); 675 676 return 0; 677} 678EXPORT_SYMBOL_GPL(uniphier_pinctrl_probe); 679 680int uniphier_pinctrl_remove(struct platform_device *pdev) 681{ 682 struct uniphier_pinctrl_priv *priv = platform_get_drvdata(pdev); 683 684 pinctrl_unregister(priv->pctldev); 685 686 return 0; 687} 688EXPORT_SYMBOL_GPL(uniphier_pinctrl_remove); 689