773 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Pin controller and GPIO driver for Amlogic Meson SoCs4 *5 * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>6 */7 8/*9 * The available pins are organized in banks (A,B,C,D,E,X,Y,Z,AO,10 * BOOT,CARD for meson6, X,Y,DV,H,Z,AO,BOOT,CARD for meson8 and11 * X,Y,DV,H,AO,BOOT,CARD,DIF for meson8b) and each bank has a12 * variable number of pins.13 *14 * The AO bank is special because it belongs to the Always-On power15 * domain which can't be powered off; the bank also uses a set of16 * registers different from the other banks.17 *18 * For each pin controller there are 4 different register ranges that19 * control the following properties of the pins:20 * 1) pin muxing21 * 2) pull enable/disable22 * 3) pull up/down23 * 4) GPIO direction, output value, input value24 *25 * In some cases the register ranges for pull enable and pull26 * direction are the same and thus there are only 3 register ranges.27 *28 * Since Meson G12A SoC, the ao register ranges for gpio, pull enable29 * and pull direction are the same, so there are only 2 register ranges.30 *31 * For the pull and GPIO configuration every bank uses a contiguous32 * set of bits in the register sets described above; the same register33 * can be shared by more banks with different offsets.34 *35 * In addition to this there are some registers shared between all36 * banks that control the IRQ functionality. This feature is not37 * supported at the moment by the driver.38 */39 40#include <linux/device.h>41#include <linux/gpio/driver.h>42#include <linux/init.h>43#include <linux/io.h>44#include <linux/of.h>45#include <linux/of_address.h>46#include <linux/pinctrl/pinconf-generic.h>47#include <linux/pinctrl/pinconf.h>48#include <linux/pinctrl/pinctrl.h>49#include <linux/pinctrl/pinmux.h>50#include <linux/platform_device.h>51#include <linux/property.h>52#include <linux/regmap.h>53#include <linux/seq_file.h>54 55#include "../core.h"56#include "../pinctrl-utils.h"57#include "pinctrl-meson.h"58 59static const unsigned int meson_bit_strides[] = {60 1, 1, 1, 1, 1, 2, 161};62 63/**64 * meson_get_bank() - find the bank containing a given pin65 *66 * @pc: the pinctrl instance67 * @pin: the pin number68 * @bank: the found bank69 *70 * Return: 0 on success, a negative value on error71 */72static int meson_get_bank(struct meson_pinctrl *pc, unsigned int pin,73 const struct meson_bank **bank)74{75 int i;76 77 for (i = 0; i < pc->data->num_banks; i++) {78 if (pin >= pc->data->banks[i].first &&79 pin <= pc->data->banks[i].last) {80 *bank = &pc->data->banks[i];81 return 0;82 }83 }84 85 return -EINVAL;86}87 88/**89 * meson_calc_reg_and_bit() - calculate register and bit for a pin90 *91 * @bank: the bank containing the pin92 * @pin: the pin number93 * @reg_type: the type of register needed (pull-enable, pull, etc...)94 * @reg: the computed register offset95 * @bit: the computed bit96 */97static void meson_calc_reg_and_bit(const struct meson_bank *bank,98 unsigned int pin,99 enum meson_reg_type reg_type,100 unsigned int *reg, unsigned int *bit)101{102 const struct meson_reg_desc *desc = &bank->regs[reg_type];103 104 *bit = (desc->bit + pin - bank->first) * meson_bit_strides[reg_type];105 *reg = (desc->reg + (*bit / 32)) * 4;106 *bit &= 0x1f;107}108 109static int meson_get_groups_count(struct pinctrl_dev *pcdev)110{111 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);112 113 return pc->data->num_groups;114}115 116static const char *meson_get_group_name(struct pinctrl_dev *pcdev,117 unsigned selector)118{119 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);120 121 return pc->data->groups[selector].name;122}123 124static int meson_get_group_pins(struct pinctrl_dev *pcdev, unsigned selector,125 const unsigned **pins, unsigned *num_pins)126{127 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);128 129 *pins = pc->data->groups[selector].pins;130 *num_pins = pc->data->groups[selector].num_pins;131 132 return 0;133}134 135static void meson_pin_dbg_show(struct pinctrl_dev *pcdev, struct seq_file *s,136 unsigned offset)137{138 seq_printf(s, " %s", dev_name(pcdev->dev));139}140 141static const struct pinctrl_ops meson_pctrl_ops = {142 .get_groups_count = meson_get_groups_count,143 .get_group_name = meson_get_group_name,144 .get_group_pins = meson_get_group_pins,145 .dt_node_to_map = pinconf_generic_dt_node_to_map_all,146 .dt_free_map = pinctrl_utils_free_map,147 .pin_dbg_show = meson_pin_dbg_show,148};149 150int meson_pmx_get_funcs_count(struct pinctrl_dev *pcdev)151{152 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);153 154 return pc->data->num_funcs;155}156EXPORT_SYMBOL_GPL(meson_pmx_get_funcs_count);157 158const char *meson_pmx_get_func_name(struct pinctrl_dev *pcdev,159 unsigned selector)160{161 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);162 163 return pc->data->funcs[selector].name;164}165EXPORT_SYMBOL_GPL(meson_pmx_get_func_name);166 167int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector,168 const char * const **groups,169 unsigned * const num_groups)170{171 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);172 173 *groups = pc->data->funcs[selector].groups;174 *num_groups = pc->data->funcs[selector].num_groups;175 176 return 0;177}178EXPORT_SYMBOL_GPL(meson_pmx_get_groups);179 180static int meson_pinconf_set_gpio_bit(struct meson_pinctrl *pc,181 unsigned int pin,182 unsigned int reg_type,183 bool arg)184{185 const struct meson_bank *bank;186 unsigned int reg, bit;187 int ret;188 189 ret = meson_get_bank(pc, pin, &bank);190 if (ret)191 return ret;192 193 meson_calc_reg_and_bit(bank, pin, reg_type, ®, &bit);194 return regmap_update_bits(pc->reg_gpio, reg, BIT(bit),195 arg ? BIT(bit) : 0);196}197 198static int meson_pinconf_get_gpio_bit(struct meson_pinctrl *pc,199 unsigned int pin,200 unsigned int reg_type)201{202 const struct meson_bank *bank;203 unsigned int reg, bit, val;204 int ret;205 206 ret = meson_get_bank(pc, pin, &bank);207 if (ret)208 return ret;209 210 meson_calc_reg_and_bit(bank, pin, reg_type, ®, &bit);211 ret = regmap_read(pc->reg_gpio, reg, &val);212 if (ret)213 return ret;214 215 return BIT(bit) & val ? 1 : 0;216}217 218static int meson_pinconf_set_output(struct meson_pinctrl *pc,219 unsigned int pin,220 bool out)221{222 return meson_pinconf_set_gpio_bit(pc, pin, MESON_REG_DIR, !out);223}224 225static int meson_pinconf_get_output(struct meson_pinctrl *pc,226 unsigned int pin)227{228 int ret = meson_pinconf_get_gpio_bit(pc, pin, MESON_REG_DIR);229 230 if (ret < 0)231 return ret;232 233 return !ret;234}235 236static int meson_pinconf_set_drive(struct meson_pinctrl *pc,237 unsigned int pin,238 bool high)239{240 return meson_pinconf_set_gpio_bit(pc, pin, MESON_REG_OUT, high);241}242 243static int meson_pinconf_get_drive(struct meson_pinctrl *pc,244 unsigned int pin)245{246 return meson_pinconf_get_gpio_bit(pc, pin, MESON_REG_OUT);247}248 249static int meson_pinconf_set_output_drive(struct meson_pinctrl *pc,250 unsigned int pin,251 bool high)252{253 int ret;254 255 ret = meson_pinconf_set_output(pc, pin, true);256 if (ret)257 return ret;258 259 return meson_pinconf_set_drive(pc, pin, high);260}261 262static int meson_pinconf_disable_bias(struct meson_pinctrl *pc,263 unsigned int pin)264{265 const struct meson_bank *bank;266 unsigned int reg, bit = 0;267 int ret;268 269 ret = meson_get_bank(pc, pin, &bank);270 if (ret)271 return ret;272 273 meson_calc_reg_and_bit(bank, pin, MESON_REG_PULLEN, ®, &bit);274 ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), 0);275 if (ret)276 return ret;277 278 return 0;279}280 281static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin,282 bool pull_up)283{284 const struct meson_bank *bank;285 unsigned int reg, bit, val = 0;286 int ret;287 288 ret = meson_get_bank(pc, pin, &bank);289 if (ret)290 return ret;291 292 meson_calc_reg_and_bit(bank, pin, MESON_REG_PULL, ®, &bit);293 if (pull_up)294 val = BIT(bit);295 296 ret = regmap_update_bits(pc->reg_pull, reg, BIT(bit), val);297 if (ret)298 return ret;299 300 meson_calc_reg_and_bit(bank, pin, MESON_REG_PULLEN, ®, &bit);301 ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), BIT(bit));302 if (ret)303 return ret;304 305 return 0;306}307 308static int meson_pinconf_set_drive_strength(struct meson_pinctrl *pc,309 unsigned int pin,310 u16 drive_strength_ua)311{312 const struct meson_bank *bank;313 unsigned int reg, bit, ds_val;314 int ret;315 316 if (!pc->reg_ds) {317 dev_err(pc->dev, "drive-strength not supported\n");318 return -ENOTSUPP;319 }320 321 ret = meson_get_bank(pc, pin, &bank);322 if (ret)323 return ret;324 325 meson_calc_reg_and_bit(bank, pin, MESON_REG_DS, ®, &bit);326 327 if (drive_strength_ua <= 500) {328 ds_val = MESON_PINCONF_DRV_500UA;329 } else if (drive_strength_ua <= 2500) {330 ds_val = MESON_PINCONF_DRV_2500UA;331 } else if (drive_strength_ua <= 3000) {332 ds_val = MESON_PINCONF_DRV_3000UA;333 } else if (drive_strength_ua <= 4000) {334 ds_val = MESON_PINCONF_DRV_4000UA;335 } else {336 dev_warn_once(pc->dev,337 "pin %u: invalid drive-strength : %d , default to 4mA\n",338 pin, drive_strength_ua);339 ds_val = MESON_PINCONF_DRV_4000UA;340 }341 342 ret = regmap_update_bits(pc->reg_ds, reg, 0x3 << bit, ds_val << bit);343 if (ret)344 return ret;345 346 return 0;347}348 349static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,350 unsigned long *configs, unsigned num_configs)351{352 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);353 enum pin_config_param param;354 unsigned int arg = 0;355 int i, ret;356 357 for (i = 0; i < num_configs; i++) {358 param = pinconf_to_config_param(configs[i]);359 360 switch (param) {361 case PIN_CONFIG_DRIVE_STRENGTH_UA:362 case PIN_CONFIG_OUTPUT_ENABLE:363 case PIN_CONFIG_OUTPUT:364 arg = pinconf_to_config_argument(configs[i]);365 break;366 367 default:368 break;369 }370 371 switch (param) {372 case PIN_CONFIG_BIAS_DISABLE:373 ret = meson_pinconf_disable_bias(pc, pin);374 break;375 case PIN_CONFIG_BIAS_PULL_UP:376 ret = meson_pinconf_enable_bias(pc, pin, true);377 break;378 case PIN_CONFIG_BIAS_PULL_DOWN:379 ret = meson_pinconf_enable_bias(pc, pin, false);380 break;381 case PIN_CONFIG_DRIVE_STRENGTH_UA:382 ret = meson_pinconf_set_drive_strength(pc, pin, arg);383 break;384 case PIN_CONFIG_OUTPUT_ENABLE:385 ret = meson_pinconf_set_output(pc, pin, arg);386 break;387 case PIN_CONFIG_OUTPUT:388 ret = meson_pinconf_set_output_drive(pc, pin, arg);389 break;390 default:391 ret = -ENOTSUPP;392 }393 394 if (ret)395 return ret;396 }397 398 return 0;399}400 401static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin)402{403 const struct meson_bank *bank;404 unsigned int reg, bit, val;405 int ret, conf;406 407 ret = meson_get_bank(pc, pin, &bank);408 if (ret)409 return ret;410 411 meson_calc_reg_and_bit(bank, pin, MESON_REG_PULLEN, ®, &bit);412 413 ret = regmap_read(pc->reg_pullen, reg, &val);414 if (ret)415 return ret;416 417 if (!(val & BIT(bit))) {418 conf = PIN_CONFIG_BIAS_DISABLE;419 } else {420 meson_calc_reg_and_bit(bank, pin, MESON_REG_PULL, ®, &bit);421 422 ret = regmap_read(pc->reg_pull, reg, &val);423 if (ret)424 return ret;425 426 if (val & BIT(bit))427 conf = PIN_CONFIG_BIAS_PULL_UP;428 else429 conf = PIN_CONFIG_BIAS_PULL_DOWN;430 }431 432 return conf;433}434 435static int meson_pinconf_get_drive_strength(struct meson_pinctrl *pc,436 unsigned int pin,437 u16 *drive_strength_ua)438{439 const struct meson_bank *bank;440 unsigned int reg, bit;441 unsigned int val;442 int ret;443 444 if (!pc->reg_ds)445 return -ENOTSUPP;446 447 ret = meson_get_bank(pc, pin, &bank);448 if (ret)449 return ret;450 451 meson_calc_reg_and_bit(bank, pin, MESON_REG_DS, ®, &bit);452 453 ret = regmap_read(pc->reg_ds, reg, &val);454 if (ret)455 return ret;456 457 switch ((val >> bit) & 0x3) {458 case MESON_PINCONF_DRV_500UA:459 *drive_strength_ua = 500;460 break;461 case MESON_PINCONF_DRV_2500UA:462 *drive_strength_ua = 2500;463 break;464 case MESON_PINCONF_DRV_3000UA:465 *drive_strength_ua = 3000;466 break;467 case MESON_PINCONF_DRV_4000UA:468 *drive_strength_ua = 4000;469 break;470 default:471 return -EINVAL;472 }473 474 return 0;475}476 477static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,478 unsigned long *config)479{480 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);481 enum pin_config_param param = pinconf_to_config_param(*config);482 u16 arg;483 int ret;484 485 switch (param) {486 case PIN_CONFIG_BIAS_DISABLE:487 case PIN_CONFIG_BIAS_PULL_DOWN:488 case PIN_CONFIG_BIAS_PULL_UP:489 if (meson_pinconf_get_pull(pc, pin) == param)490 arg = 1;491 else492 return -EINVAL;493 break;494 case PIN_CONFIG_DRIVE_STRENGTH_UA:495 ret = meson_pinconf_get_drive_strength(pc, pin, &arg);496 if (ret)497 return ret;498 break;499 case PIN_CONFIG_OUTPUT_ENABLE:500 ret = meson_pinconf_get_output(pc, pin);501 if (ret <= 0)502 return -EINVAL;503 arg = 1;504 break;505 case PIN_CONFIG_OUTPUT:506 ret = meson_pinconf_get_output(pc, pin);507 if (ret <= 0)508 return -EINVAL;509 510 ret = meson_pinconf_get_drive(pc, pin);511 if (ret < 0)512 return -EINVAL;513 514 arg = ret;515 break;516 517 default:518 return -ENOTSUPP;519 }520 521 *config = pinconf_to_config_packed(param, arg);522 dev_dbg(pc->dev, "pinconf for pin %u is %lu\n", pin, *config);523 524 return 0;525}526 527static int meson_pinconf_group_set(struct pinctrl_dev *pcdev,528 unsigned int num_group,529 unsigned long *configs, unsigned num_configs)530{531 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);532 const struct meson_pmx_group *group = &pc->data->groups[num_group];533 int i;534 535 dev_dbg(pc->dev, "set pinconf for group %s\n", group->name);536 537 for (i = 0; i < group->num_pins; i++) {538 meson_pinconf_set(pcdev, group->pins[i], configs,539 num_configs);540 }541 542 return 0;543}544 545static int meson_pinconf_group_get(struct pinctrl_dev *pcdev,546 unsigned int group, unsigned long *config)547{548 return -ENOTSUPP;549}550 551static const struct pinconf_ops meson_pinconf_ops = {552 .pin_config_get = meson_pinconf_get,553 .pin_config_set = meson_pinconf_set,554 .pin_config_group_get = meson_pinconf_group_get,555 .pin_config_group_set = meson_pinconf_group_set,556 .is_generic = true,557};558 559static int meson_gpio_get_direction(struct gpio_chip *chip, unsigned gpio)560{561 struct meson_pinctrl *pc = gpiochip_get_data(chip);562 int ret;563 564 ret = meson_pinconf_get_output(pc, gpio);565 if (ret < 0)566 return ret;567 568 return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;569}570 571static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)572{573 return meson_pinconf_set_output(gpiochip_get_data(chip), gpio, false);574}575 576static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,577 int value)578{579 return meson_pinconf_set_output_drive(gpiochip_get_data(chip),580 gpio, value);581}582 583static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)584{585 meson_pinconf_set_drive(gpiochip_get_data(chip), gpio, value);586}587 588static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)589{590 struct meson_pinctrl *pc = gpiochip_get_data(chip);591 const struct meson_bank *bank;592 unsigned int reg, bit, val;593 int ret;594 595 ret = meson_get_bank(pc, gpio, &bank);596 if (ret)597 return ret;598 599 meson_calc_reg_and_bit(bank, gpio, MESON_REG_IN, ®, &bit);600 regmap_read(pc->reg_gpio, reg, &val);601 602 return !!(val & BIT(bit));603}604 605static int meson_gpiolib_register(struct meson_pinctrl *pc)606{607 int ret;608 609 pc->chip.label = pc->data->name;610 pc->chip.parent = pc->dev;611 pc->chip.fwnode = pc->fwnode;612 pc->chip.request = gpiochip_generic_request;613 pc->chip.free = gpiochip_generic_free;614 pc->chip.set_config = gpiochip_generic_config;615 pc->chip.get_direction = meson_gpio_get_direction;616 pc->chip.direction_input = meson_gpio_direction_input;617 pc->chip.direction_output = meson_gpio_direction_output;618 pc->chip.get = meson_gpio_get;619 pc->chip.set = meson_gpio_set;620 pc->chip.base = -1;621 pc->chip.ngpio = pc->data->num_pins;622 pc->chip.can_sleep = false;623 624 ret = gpiochip_add_data(&pc->chip, pc);625 if (ret) {626 dev_err(pc->dev, "can't add gpio chip %s\n",627 pc->data->name);628 return ret;629 }630 631 return 0;632}633 634static struct regmap_config meson_regmap_config = {635 .reg_bits = 32,636 .val_bits = 32,637 .reg_stride = 4,638};639 640static struct regmap *meson_map_resource(struct meson_pinctrl *pc,641 struct device_node *node, char *name)642{643 struct resource res;644 void __iomem *base;645 int i;646 647 i = of_property_match_string(node, "reg-names", name);648 if (of_address_to_resource(node, i, &res))649 return NULL;650 651 base = devm_ioremap_resource(pc->dev, &res);652 if (IS_ERR(base))653 return ERR_CAST(base);654 655 meson_regmap_config.max_register = resource_size(&res) - 4;656 meson_regmap_config.name = devm_kasprintf(pc->dev, GFP_KERNEL,657 "%pOFn-%s", node,658 name);659 if (!meson_regmap_config.name)660 return ERR_PTR(-ENOMEM);661 662 return devm_regmap_init_mmio(pc->dev, base, &meson_regmap_config);663}664 665static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc)666{667 struct device_node *gpio_np;668 unsigned int chips;669 670 chips = gpiochip_node_count(pc->dev);671 if (!chips) {672 dev_err(pc->dev, "no gpio node found\n");673 return -EINVAL;674 }675 if (chips > 1) {676 dev_err(pc->dev, "multiple gpio nodes\n");677 return -EINVAL;678 }679 680 pc->fwnode = gpiochip_node_get_first(pc->dev);681 gpio_np = to_of_node(pc->fwnode);682 683 pc->reg_mux = meson_map_resource(pc, gpio_np, "mux");684 if (IS_ERR_OR_NULL(pc->reg_mux)) {685 dev_err(pc->dev, "mux registers not found\n");686 return pc->reg_mux ? PTR_ERR(pc->reg_mux) : -ENOENT;687 }688 689 pc->reg_gpio = meson_map_resource(pc, gpio_np, "gpio");690 if (IS_ERR_OR_NULL(pc->reg_gpio)) {691 dev_err(pc->dev, "gpio registers not found\n");692 return pc->reg_gpio ? PTR_ERR(pc->reg_gpio) : -ENOENT;693 }694 695 pc->reg_pull = meson_map_resource(pc, gpio_np, "pull");696 if (IS_ERR(pc->reg_pull))697 pc->reg_pull = NULL;698 699 pc->reg_pullen = meson_map_resource(pc, gpio_np, "pull-enable");700 if (IS_ERR(pc->reg_pullen))701 pc->reg_pullen = NULL;702 703 pc->reg_ds = meson_map_resource(pc, gpio_np, "ds");704 if (IS_ERR(pc->reg_ds)) {705 dev_dbg(pc->dev, "ds registers not found - skipping\n");706 pc->reg_ds = NULL;707 }708 709 if (pc->data->parse_dt)710 return pc->data->parse_dt(pc);711 712 return 0;713}714 715int meson8_aobus_parse_dt_extra(struct meson_pinctrl *pc)716{717 if (!pc->reg_pull)718 return -EINVAL;719 720 pc->reg_pullen = pc->reg_pull;721 722 return 0;723}724EXPORT_SYMBOL_GPL(meson8_aobus_parse_dt_extra);725 726int meson_a1_parse_dt_extra(struct meson_pinctrl *pc)727{728 pc->reg_pull = pc->reg_gpio;729 pc->reg_pullen = pc->reg_gpio;730 pc->reg_ds = pc->reg_gpio;731 732 return 0;733}734EXPORT_SYMBOL_GPL(meson_a1_parse_dt_extra);735 736int meson_pinctrl_probe(struct platform_device *pdev)737{738 struct device *dev = &pdev->dev;739 struct meson_pinctrl *pc;740 int ret;741 742 pc = devm_kzalloc(dev, sizeof(struct meson_pinctrl), GFP_KERNEL);743 if (!pc)744 return -ENOMEM;745 746 pc->dev = dev;747 pc->data = (struct meson_pinctrl_data *) of_device_get_match_data(dev);748 749 ret = meson_pinctrl_parse_dt(pc);750 if (ret)751 return ret;752 753 pc->desc.name = "pinctrl-meson";754 pc->desc.owner = THIS_MODULE;755 pc->desc.pctlops = &meson_pctrl_ops;756 pc->desc.pmxops = pc->data->pmx_ops;757 pc->desc.confops = &meson_pinconf_ops;758 pc->desc.pins = pc->data->pins;759 pc->desc.npins = pc->data->num_pins;760 761 pc->pcdev = devm_pinctrl_register(pc->dev, &pc->desc, pc);762 if (IS_ERR(pc->pcdev)) {763 dev_err(pc->dev, "can't register pinctrl device");764 return PTR_ERR(pc->pcdev);765 }766 767 return meson_gpiolib_register(pc);768}769EXPORT_SYMBOL_GPL(meson_pinctrl_probe);770 771MODULE_DESCRIPTION("Amlogic Meson SoCs core pinctrl driver");772MODULE_LICENSE("GPL v2");773