mirror of
https://github.com/torvalds/linux.git
synced 2025-01-01 07:42:07 +00:00
pinctrl: intel: Do pin translation in other GPIO operations as well
For some reason I thought GPIOLIB handles translation from GPIO ranges
to pinctrl pins but it turns out not to be the case. This means that
when GPIOs operations are performed for a pin controller having a custom
GPIO base such as Cannon Lake and Ice Lake incorrect pin number gets
used internally.
Fix this in the same way we did for lock/unlock IRQ operations and
translate the GPIO number to pin before using it.
Fixes: a60eac3239
("pinctrl: intel: Allow custom GPIO base for pad groups")
Reported-by: Rajat Jain <rajatja@google.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Rajat Jain <rajatja@google.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
8e2aac3337
commit
96147db1e1
@ -747,86 +747,6 @@ static const struct pinctrl_desc intel_pinctrl_desc = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
|
|
||||||
void __iomem *reg;
|
|
||||||
u32 padcfg0;
|
|
||||||
|
|
||||||
reg = intel_get_padcfg(pctrl, offset, PADCFG0);
|
|
||||||
if (!reg)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
padcfg0 = readl(reg);
|
|
||||||
if (!(padcfg0 & PADCFG0_GPIOTXDIS))
|
|
||||||
return !!(padcfg0 & PADCFG0_GPIOTXSTATE);
|
|
||||||
|
|
||||||
return !!(padcfg0 & PADCFG0_GPIORXSTATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
||||||
{
|
|
||||||
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
|
|
||||||
unsigned long flags;
|
|
||||||
void __iomem *reg;
|
|
||||||
u32 padcfg0;
|
|
||||||
|
|
||||||
reg = intel_get_padcfg(pctrl, offset, PADCFG0);
|
|
||||||
if (!reg)
|
|
||||||
return;
|
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&pctrl->lock, flags);
|
|
||||||
padcfg0 = readl(reg);
|
|
||||||
if (value)
|
|
||||||
padcfg0 |= PADCFG0_GPIOTXSTATE;
|
|
||||||
else
|
|
||||||
padcfg0 &= ~PADCFG0_GPIOTXSTATE;
|
|
||||||
writel(padcfg0, reg);
|
|
||||||
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
|
||||||
{
|
|
||||||
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
|
|
||||||
void __iomem *reg;
|
|
||||||
u32 padcfg0;
|
|
||||||
|
|
||||||
reg = intel_get_padcfg(pctrl, offset, PADCFG0);
|
|
||||||
if (!reg)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
padcfg0 = readl(reg);
|
|
||||||
|
|
||||||
if (padcfg0 & PADCFG0_PMODE_MASK)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return !!(padcfg0 & PADCFG0_GPIOTXDIS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
return pinctrl_gpio_direction_input(chip->base + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
|
||||||
int value)
|
|
||||||
{
|
|
||||||
intel_gpio_set(chip, offset, value);
|
|
||||||
return pinctrl_gpio_direction_output(chip->base + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct gpio_chip intel_gpio_chip = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.request = gpiochip_generic_request,
|
|
||||||
.free = gpiochip_generic_free,
|
|
||||||
.get_direction = intel_gpio_get_direction,
|
|
||||||
.direction_input = intel_gpio_direction_input,
|
|
||||||
.direction_output = intel_gpio_direction_output,
|
|
||||||
.get = intel_gpio_get,
|
|
||||||
.set = intel_gpio_set,
|
|
||||||
.set_config = gpiochip_generic_config,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* intel_gpio_to_pin() - Translate from GPIO offset to pin number
|
* intel_gpio_to_pin() - Translate from GPIO offset to pin number
|
||||||
* @pctrl: Pinctrl structure
|
* @pctrl: Pinctrl structure
|
||||||
@ -872,6 +792,101 @@ static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
|
||||||
|
void __iomem *reg;
|
||||||
|
u32 padcfg0;
|
||||||
|
int pin;
|
||||||
|
|
||||||
|
pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL);
|
||||||
|
if (pin < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
reg = intel_get_padcfg(pctrl, pin, PADCFG0);
|
||||||
|
if (!reg)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
padcfg0 = readl(reg);
|
||||||
|
if (!(padcfg0 & PADCFG0_GPIOTXDIS))
|
||||||
|
return !!(padcfg0 & PADCFG0_GPIOTXSTATE);
|
||||||
|
|
||||||
|
return !!(padcfg0 & PADCFG0_GPIORXSTATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
{
|
||||||
|
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
|
||||||
|
unsigned long flags;
|
||||||
|
void __iomem *reg;
|
||||||
|
u32 padcfg0;
|
||||||
|
int pin;
|
||||||
|
|
||||||
|
pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL);
|
||||||
|
if (pin < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
reg = intel_get_padcfg(pctrl, pin, PADCFG0);
|
||||||
|
if (!reg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
raw_spin_lock_irqsave(&pctrl->lock, flags);
|
||||||
|
padcfg0 = readl(reg);
|
||||||
|
if (value)
|
||||||
|
padcfg0 |= PADCFG0_GPIOTXSTATE;
|
||||||
|
else
|
||||||
|
padcfg0 &= ~PADCFG0_GPIOTXSTATE;
|
||||||
|
writel(padcfg0, reg);
|
||||||
|
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||||
|
{
|
||||||
|
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
|
||||||
|
void __iomem *reg;
|
||||||
|
u32 padcfg0;
|
||||||
|
int pin;
|
||||||
|
|
||||||
|
pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL);
|
||||||
|
if (pin < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
reg = intel_get_padcfg(pctrl, pin, PADCFG0);
|
||||||
|
if (!reg)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
padcfg0 = readl(reg);
|
||||||
|
|
||||||
|
if (padcfg0 & PADCFG0_PMODE_MASK)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return !!(padcfg0 & PADCFG0_GPIOTXDIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
return pinctrl_gpio_direction_input(chip->base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
intel_gpio_set(chip, offset, value);
|
||||||
|
return pinctrl_gpio_direction_output(chip->base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct gpio_chip intel_gpio_chip = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.request = gpiochip_generic_request,
|
||||||
|
.free = gpiochip_generic_free,
|
||||||
|
.get_direction = intel_gpio_get_direction,
|
||||||
|
.direction_input = intel_gpio_direction_input,
|
||||||
|
.direction_output = intel_gpio_direction_output,
|
||||||
|
.get = intel_gpio_get,
|
||||||
|
.set = intel_gpio_set,
|
||||||
|
.set_config = gpiochip_generic_config,
|
||||||
|
};
|
||||||
|
|
||||||
static int intel_gpio_irq_reqres(struct irq_data *d)
|
static int intel_gpio_irq_reqres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||||
|
Loading…
Reference in New Issue
Block a user