static int abx500_set_mode()

in nomadik/pinctrl-abx500.c [239:357]


static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
			   unsigned gpio, int alt_setting)
{
	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
	struct alternate_functions af = pct->soc->alternate_functions[gpio];
	int ret;
	int val;
	unsigned offset;

	const char *modes[] = {
		[ABX500_DEFAULT]	= "default",
		[ABX500_ALT_A]		= "altA",
		[ABX500_ALT_B]		= "altB",
		[ABX500_ALT_C]		= "altC",
	};

	/* sanity check */
	if (((alt_setting == ABX500_ALT_A) && (af.gpiosel_bit == UNUSED)) ||
	    ((alt_setting == ABX500_ALT_B) && (af.alt_bit1 == UNUSED)) ||
	    ((alt_setting == ABX500_ALT_C) && (af.alt_bit2 == UNUSED))) {
		dev_dbg(pct->dev, "pin %d doesn't support %s mode\n", gpio,
				modes[alt_setting]);
		return -EINVAL;
	}

	/* on ABx5xx, there is no GPIO0, so adjust the offset */
	offset = gpio - 1;

	switch (alt_setting) {
	case ABX500_DEFAULT:
		/*
		 * for ABx5xx family, default mode is always selected by
		 * writing 0 to GPIOSELx register, except for pins which
		 * support at least ALT_B mode, default mode is selected
		 * by writing 1 to GPIOSELx register
		 */
		val = 0;
		if (af.alt_bit1 != UNUSED)
			val++;

		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
					   offset, val);
		break;

	case ABX500_ALT_A:
		/*
		 * for ABx5xx family, alt_a mode is always selected by
		 * writing 1 to GPIOSELx register, except for pins which
		 * support at least ALT_B mode, alt_a mode is selected
		 * by writing 0 to GPIOSELx register and 0 in ALTFUNC
		 * register
		 */
		if (af.alt_bit1 != UNUSED) {
			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
					offset, 0);
			if (ret < 0)
				goto out;

			ret = abx500_gpio_set_bits(chip,
					AB8500_GPIO_ALTFUN_REG,
					af.alt_bit1,
					!!(af.alta_val & BIT(0)));
			if (ret < 0)
				goto out;

			if (af.alt_bit2 != UNUSED)
				ret = abx500_gpio_set_bits(chip,
					AB8500_GPIO_ALTFUN_REG,
					af.alt_bit2,
					!!(af.alta_val & BIT(1)));
		} else
			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
					offset, 1);
		break;

	case ABX500_ALT_B:
		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
				offset, 0);
		if (ret < 0)
			goto out;

		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
				af.alt_bit1, !!(af.altb_val & BIT(0)));
		if (ret < 0)
			goto out;

		if (af.alt_bit2 != UNUSED)
			ret = abx500_gpio_set_bits(chip,
					AB8500_GPIO_ALTFUN_REG,
					af.alt_bit2,
					!!(af.altb_val & BIT(1)));
		break;

	case ABX500_ALT_C:
		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
				offset, 0);
		if (ret < 0)
			goto out;

		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
				af.alt_bit2, !!(af.altc_val & BIT(0)));
		if (ret < 0)
			goto out;

		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
				af.alt_bit2, !!(af.altc_val & BIT(1)));
		break;

	default:
		dev_dbg(pct->dev, "unknown alt_setting %d\n", alt_setting);

		return -EINVAL;
	}
out:
	if (ret < 0)
		dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);

	return ret;
}