brintos

brintos / linux-shallow public Read only

0
0
Text · 18.5 KiB · 253a0cc Raw
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, &reg, &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, &reg, &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, &reg, &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, &reg, &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, &reg, &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, &reg, &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, &reg, &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, &reg, &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, &reg, &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, &reg, &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