Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9de3a3a7 authored by Li Jin's avatar Li Jin Committed by Greg Kroah-Hartman
Browse files

pinctrl: iproc-gpio: Fix incorrect pinconf configurations



[ Upstream commit 398a1f50e3c731586182fd52b834103b0aa2f826 ]

Fix drive strength for AON/CRMU controller; fix pull-up/down setting
for CCM/CDRU controller.

Fixes: 616043d5 ("pinctrl: Rename gpio driver from cygnus to iproc")
Signed-off-by: default avatarLi Jin <li.jin@broadcom.com>
Link: https://lore.kernel.org/r/1567054348-19685-2-git-send-email-srinath.mannam@broadcom.com


Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 4e132b2f
Loading
Loading
Loading
Loading
+77 −19
Original line number Diff line number Diff line
@@ -54,8 +54,12 @@
/* drive strength control for ASIU GPIO */
#define IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58

/* drive strength control for CCM/CRMU (AON) GPIO */
#define IPROC_GPIO_DRV0_CTRL_OFFSET  0x00
/* pinconf for CCM GPIO */
#define IPROC_GPIO_PULL_DN_OFFSET   0x10
#define IPROC_GPIO_PULL_UP_OFFSET   0x14

/* pinconf for CRMU(aon) GPIO and CCM GPIO*/
#define IPROC_GPIO_DRV_CTRL_OFFSET  0x00

#define GPIO_BANK_SIZE 0x200
#define NGPIOS_PER_BANK 32
@@ -76,6 +80,12 @@ enum iproc_pinconf_param {
	IPROC_PINCON_MAX,
};

enum iproc_pinconf_ctrl_type {
	IOCTRL_TYPE_AON = 1,
	IOCTRL_TYPE_CDRU,
	IOCTRL_TYPE_INVALID,
};

/*
 * Iproc GPIO core
 *
@@ -100,6 +110,7 @@ struct iproc_gpio {

	void __iomem *base;
	void __iomem *io_ctrl;
	enum iproc_pinconf_ctrl_type io_ctrl_type;

	raw_spinlock_t lock;

@@ -461,20 +472,44 @@ static const struct pinctrl_ops iproc_pctrl_ops = {
static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio,
				bool disable, bool pull_up)
{
	void __iomem *base;
	unsigned long flags;
	unsigned int shift;
	u32 val_1, val_2;

	raw_spin_lock_irqsave(&chip->lock, flags);
	if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) {
		base = chip->io_ctrl;
		shift = IPROC_GPIO_SHIFT(gpio);

		val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET);
		val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET);
		if (disable) {
		iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, false);
			/* no pull-up or pull-down */
			val_1 &= ~BIT(shift);
			val_2 &= ~BIT(shift);
		} else if (pull_up) {
			val_1 |= BIT(shift);
			val_2 &= ~BIT(shift);
		} else {
			val_1 &= ~BIT(shift);
			val_2 |= BIT(shift);
		}
		writel(val_1, base + IPROC_GPIO_PULL_UP_OFFSET);
		writel(val_2, base + IPROC_GPIO_PULL_DN_OFFSET);
	} else {
		if (disable) {
			iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio,
				      false);
		} else {
			iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio,
				      pull_up);
		iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, true);
			iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio,
				      true);
		}
	}

	raw_spin_unlock_irqrestore(&chip->lock, flags);

	dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up);

	return 0;
@@ -483,14 +518,35 @@ static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio,
static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio,
				 bool *disable, bool *pull_up)
{
	void __iomem *base;
	unsigned long flags;
	unsigned int shift;
	u32 val_1, val_2;

	raw_spin_lock_irqsave(&chip->lock, flags);
	if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) {
		base = chip->io_ctrl;
		shift = IPROC_GPIO_SHIFT(gpio);

		val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET) & BIT(shift);
		val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET) & BIT(shift);

		*pull_up = val_1 ? true : false;
		*disable = (val_1 | val_2) ? false : true;

	} else {
		*disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio);
		*pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio);
	}
	raw_spin_unlock_irqrestore(&chip->lock, flags);
}

#define DRV_STRENGTH_OFFSET(gpio, bit, type)  ((type) == IOCTRL_TYPE_AON ? \
	((2 - (bit)) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \
	((type) == IOCTRL_TYPE_CDRU) ? \
	((bit) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \
	((bit) * 4 + IPROC_GPIO_REG(gpio, IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET)))

static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,
				    unsigned strength)
{
@@ -505,11 +561,8 @@ static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,

	if (chip->io_ctrl) {
		base = chip->io_ctrl;
		offset = IPROC_GPIO_DRV0_CTRL_OFFSET;
	} else {
		base = chip->base;
		offset = IPROC_GPIO_REG(gpio,
					 IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET);
	}

	shift = IPROC_GPIO_SHIFT(gpio);
@@ -520,11 +573,11 @@ static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,
	raw_spin_lock_irqsave(&chip->lock, flags);
	strength = (strength / 2) - 1;
	for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
		offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type);
		val = readl(base + offset);
		val &= ~BIT(shift);
		val |= ((strength >> i) & 0x1) << shift;
		writel(val, base + offset);
		offset += 4;
	}
	raw_spin_unlock_irqrestore(&chip->lock, flags);

@@ -541,11 +594,8 @@ static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio,

	if (chip->io_ctrl) {
		base = chip->io_ctrl;
		offset = IPROC_GPIO_DRV0_CTRL_OFFSET;
	} else {
		base = chip->base;
		offset = IPROC_GPIO_REG(gpio,
					 IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET);
	}

	shift = IPROC_GPIO_SHIFT(gpio);
@@ -553,10 +603,10 @@ static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio,
	raw_spin_lock_irqsave(&chip->lock, flags);
	*strength = 0;
	for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
		offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type);
		val = readl(base + offset) & BIT(shift);
		val >>= shift;
		*strength += (val << i);
		offset += 4;
	}

	/* convert to mA */
@@ -734,6 +784,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
	u32 ngpios, pinconf_disable_mask = 0;
	int irq, ret;
	bool no_pinconf = false;
	enum iproc_pinconf_ctrl_type io_ctrl_type = IOCTRL_TYPE_INVALID;

	/* NSP does not support drive strength config */
	if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio"))
@@ -764,8 +815,15 @@ static int iproc_gpio_probe(struct platform_device *pdev)
			dev_err(dev, "unable to map I/O memory\n");
			return PTR_ERR(chip->io_ctrl);
		}
		if (of_device_is_compatible(dev->of_node,
					    "brcm,cygnus-ccm-gpio"))
			io_ctrl_type = IOCTRL_TYPE_CDRU;
		else
			io_ctrl_type = IOCTRL_TYPE_AON;
	}

	chip->io_ctrl_type = io_ctrl_type;

	if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
		dev_err(&pdev->dev, "missing ngpios DT property\n");
		return -ENODEV;