intel-pinctrl for v5.17-3
* Intel Baytrail and Cherryview IRQ related fixes The following is an automated git shortlog grouped by driver: baytrail: - Set IRQCHIP_SET_TYPE_MASKED flag on the irqchip cherryview: - Use temporary variable for struct device - Do not allow the same interrupt line to be used by 2 pins - Don't use selection 0 to mark an interrupt line as unused -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEqaflIX74DDDzMJJtb7wzTHR8rCgFAmG6DMEACgkQb7wzTHR8 rCjNaw/+MnE7sIpBZ1143N+T7qidGSLZkOW13OQOnreSIhjUVRrxFGAj5Iy6kRJA dIsZn/ALXiAlfM1iFar9vhVLznoA9uzfWRu3mfTmCfmgiv+N2XDMg+bVrwoHf5s3 FLrTuNJKL34MAXAuTgIaGWEcpAwfrYUwY0saka3fgsj70lE8/+WWG7ZxU57E3ra4 /q+2QGM/3oyqe1R2n9TJbrsWUS2aXZE3EMWzyiAmWJcsC9cbYjKBz75mpuyysBAH chikafxJ9aovhQhtus6Hbnq2IsD3G0FpOinhZRsArZoIntEgXO/GDNDvulY9qB8Z anJHRjCD8rPv8dJk9XK+ad/uqkPZct1IpbtWSnl9s1T4Gf+SJGrEd61Kyc7Pau9h 4IMINIlCTqmPKyw7qEIsbGlQfTtvhAhNT3uRbQDjKyde+HhVtYEngwcPWGyFAPNx rj39KYkekcENZ+IQzhKmLJ3/LxFwiiU3lYtOU9oa1Xulfa/BHtdaBCbUIjuenXF6 FKJkBfqHtwE3xOIH42F9ETA9zv8alVMp6kOt4JMTY7DNyKCzaHRM4KPWT9m1NaDa JF8djmjVIQzl102MQKJxjE4y3RWyHH3e/V+itFBE/142t8CR4XTJdUgkZzGqo6V3 aGvr4oyia66b4sKureuvYLnEHnHFH2lxbgyg4YuSczwEKCvyBFo= =8Crg -----END PGP SIGNATURE----- Merge tag 'intel-pinctrl-v5.17-3' of gitolite.kernel.org:pub/scm/linux/kernel/git/pinctrl/intel into devel intel-pinctrl for v5.17-3 * Intel Baytrail and Cherryview IRQ related fixes The following is an automated git shortlog grouped by driver: baytrail: - Set IRQCHIP_SET_TYPE_MASKED flag on the irqchip cherryview: - Use temporary variable for struct device - Do not allow the same interrupt line to be used by 2 pins - Don't use selection 0 to mark an interrupt line as unused
This commit is contained in:
commit
f9b94d2426
|
@ -1577,7 +1577,7 @@ static int byt_gpio_probe(struct intel_pinctrl *vg)
|
|||
vg->irqchip.irq_mask = byt_irq_mask,
|
||||
vg->irqchip.irq_unmask = byt_irq_unmask,
|
||||
vg->irqchip.irq_set_type = byt_irq_type,
|
||||
vg->irqchip.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
vg->irqchip.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED,
|
||||
|
||||
girq = &gc->irq;
|
||||
girq->chip = &vg->irqchip;
|
||||
|
|
|
@ -73,6 +73,8 @@ struct intel_pad_context {
|
|||
u32 padctrl1;
|
||||
};
|
||||
|
||||
#define CHV_INVALID_HWIRQ ((unsigned int)INVALID_HWIRQ)
|
||||
|
||||
/**
|
||||
* struct intel_community_context - community context for Cherryview
|
||||
* @intr_lines: Mapping between 16 HW interrupt wires and GPIO offset (in GPIO number space)
|
||||
|
@ -709,6 +711,7 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
|||
unsigned int function, unsigned int group)
|
||||
{
|
||||
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct device *dev = pctrl->dev;
|
||||
const struct intel_pingroup *grp;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
@ -720,9 +723,8 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
|||
/* Check first that the pad is not locked */
|
||||
for (i = 0; i < grp->npins; i++) {
|
||||
if (chv_pad_locked(pctrl, grp->pins[i])) {
|
||||
dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n",
|
||||
grp->pins[i]);
|
||||
raw_spin_unlock_irqrestore(&chv_lock, flags);
|
||||
dev_warn(dev, "unable to set mode for locked pin %u\n", grp->pins[i]);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
@ -757,8 +759,8 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
|||
value |= CHV_PADCTRL1_INVRXTX_TXENABLE;
|
||||
chv_writel(pctrl, pin, CHV_PADCTRL1, value);
|
||||
|
||||
dev_dbg(pctrl->dev, "configured pin %u mode %u OE %sinverted\n",
|
||||
pin, mode, invert_oe ? "" : "not ");
|
||||
dev_dbg(dev, "configured pin %u mode %u OE %sinverted\n", pin, mode,
|
||||
invert_oe ? "" : "not ");
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&chv_lock, flags);
|
||||
|
@ -812,7 +814,7 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
|
|||
/* Reset the interrupt mapping */
|
||||
for (i = 0; i < ARRAY_SIZE(cctx->intr_lines); i++) {
|
||||
if (cctx->intr_lines[i] == offset) {
|
||||
cctx->intr_lines[i] = 0;
|
||||
cctx->intr_lines[i] = CHV_INVALID_HWIRQ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1058,6 +1060,7 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
|||
unsigned long *configs, unsigned int nconfigs)
|
||||
{
|
||||
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct device *dev = pctrl->dev;
|
||||
enum pin_config_param param;
|
||||
int i, ret;
|
||||
u32 arg;
|
||||
|
@ -1094,8 +1097,7 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
dev_dbg(pctrl->dev, "pin %d set config %d arg %u\n", pin,
|
||||
param, arg);
|
||||
dev_dbg(dev, "pin %d set config %d arg %u\n", pin, param, arg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1302,6 +1304,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
|
|||
if (irqd_get_trigger_type(d) == IRQ_TYPE_NONE) {
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
|
||||
struct device *dev = pctrl->dev;
|
||||
struct intel_community_context *cctx = &pctrl->context.communities[0];
|
||||
unsigned int pin = irqd_to_hwirq(d);
|
||||
irq_flow_handler_t handler;
|
||||
|
@ -1319,8 +1322,10 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
|
|||
else
|
||||
handler = handle_edge_irq;
|
||||
|
||||
if (!cctx->intr_lines[intsel]) {
|
||||
if (cctx->intr_lines[intsel] == CHV_INVALID_HWIRQ) {
|
||||
irq_set_handler_locked(d, handler);
|
||||
dev_dbg(dev, "using interrupt line %u for IRQ_TYPE_NONE on pin %u\n",
|
||||
intsel, pin);
|
||||
cctx->intr_lines[intsel] = pin;
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&chv_lock, flags);
|
||||
|
@ -1330,17 +1335,74 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int chv_gpio_set_intr_line(struct intel_pinctrl *pctrl, unsigned int pin)
|
||||
{
|
||||
struct device *dev = pctrl->dev;
|
||||
struct intel_community_context *cctx = &pctrl->context.communities[0];
|
||||
const struct intel_community *community = &pctrl->communities[0];
|
||||
u32 value, intsel;
|
||||
int i;
|
||||
|
||||
value = chv_readl(pctrl, pin, CHV_PADCTRL0);
|
||||
intsel = (value & CHV_PADCTRL0_INTSEL_MASK) >> CHV_PADCTRL0_INTSEL_SHIFT;
|
||||
|
||||
if (cctx->intr_lines[intsel] == pin)
|
||||
return 0;
|
||||
|
||||
if (cctx->intr_lines[intsel] == CHV_INVALID_HWIRQ) {
|
||||
dev_dbg(dev, "using interrupt line %u for pin %u\n", intsel, pin);
|
||||
cctx->intr_lines[intsel] = pin;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The interrupt line selected by the BIOS is already in use by
|
||||
* another pin, this is a known BIOS bug found on several models.
|
||||
* But this may also be caused by Linux deciding to use a pin as
|
||||
* IRQ which was not expected to be used as such by the BIOS authors,
|
||||
* so log this at info level only.
|
||||
*/
|
||||
dev_info(dev, "interrupt line %u is used by both pin %u and pin %u\n", intsel,
|
||||
cctx->intr_lines[intsel], pin);
|
||||
|
||||
if (chv_pad_locked(pctrl, pin))
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* The BIOS fills the interrupt lines from 0 counting up, start at
|
||||
* the other end to find a free interrupt line to workaround this.
|
||||
*/
|
||||
for (i = community->nirqs - 1; i >= 0; i--) {
|
||||
if (cctx->intr_lines[i] == CHV_INVALID_HWIRQ)
|
||||
break;
|
||||
}
|
||||
if (i < 0)
|
||||
return -EBUSY;
|
||||
|
||||
dev_info(dev, "changing the interrupt line for pin %u to %d\n", pin, i);
|
||||
|
||||
value = (value & ~CHV_PADCTRL0_INTSEL_MASK) | (i << CHV_PADCTRL0_INTSEL_SHIFT);
|
||||
chv_writel(pctrl, pin, CHV_PADCTRL0, value);
|
||||
cctx->intr_lines[i] = pin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int chv_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
|
||||
struct intel_community_context *cctx = &pctrl->context.communities[0];
|
||||
unsigned int pin = irqd_to_hwirq(d);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
raw_spin_lock_irqsave(&chv_lock, flags);
|
||||
|
||||
ret = chv_gpio_set_intr_line(pctrl, pin);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* Pins which can be used as shared interrupt are configured in
|
||||
* BIOS. Driver trusts BIOS configurations and assigns different
|
||||
|
@ -1375,26 +1437,22 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned int type)
|
|||
chv_writel(pctrl, pin, CHV_PADCTRL1, value);
|
||||
}
|
||||
|
||||
value = chv_readl(pctrl, pin, CHV_PADCTRL0);
|
||||
value &= CHV_PADCTRL0_INTSEL_MASK;
|
||||
value >>= CHV_PADCTRL0_INTSEL_SHIFT;
|
||||
|
||||
cctx->intr_lines[value] = pin;
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_BOTH)
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
else if (type & IRQ_TYPE_LEVEL_MASK)
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
|
||||
out_unlock:
|
||||
raw_spin_unlock_irqrestore(&chv_lock, flags);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void chv_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
|
||||
struct device *dev = pctrl->dev;
|
||||
const struct intel_community *community = &pctrl->communities[0];
|
||||
struct intel_community_context *cctx = &pctrl->context.communities[0];
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
|
@ -1412,6 +1470,11 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
|
|||
unsigned int offset;
|
||||
|
||||
offset = cctx->intr_lines[intr_line];
|
||||
if (offset == CHV_INVALID_HWIRQ) {
|
||||
dev_err(dev, "interrupt on unused interrupt line %u\n", intr_line);
|
||||
continue;
|
||||
}
|
||||
|
||||
generic_handle_domain_irq(gc->irq.domain, offset);
|
||||
}
|
||||
|
||||
|
@ -1512,17 +1575,16 @@ static int chv_gpio_irq_init_hw(struct gpio_chip *chip)
|
|||
static int chv_gpio_add_pin_ranges(struct gpio_chip *chip)
|
||||
{
|
||||
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
|
||||
struct device *dev = pctrl->dev;
|
||||
const struct intel_community *community = &pctrl->communities[0];
|
||||
const struct intel_padgroup *gpp;
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < community->ngpps; i++) {
|
||||
gpp = &community->gpps[i];
|
||||
ret = gpiochip_add_pin_range(chip, dev_name(pctrl->dev),
|
||||
gpp->base, gpp->base,
|
||||
gpp->size);
|
||||
ret = gpiochip_add_pin_range(chip, dev_name(dev), gpp->base, gpp->base, gpp->size);
|
||||
if (ret) {
|
||||
dev_err(pctrl->dev, "failed to add GPIO pin range\n");
|
||||
dev_err(dev, "failed to add GPIO pin range\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -1535,15 +1597,16 @@ static int chv_gpio_probe(struct intel_pinctrl *pctrl, int irq)
|
|||
const struct intel_community *community = &pctrl->communities[0];
|
||||
const struct intel_padgroup *gpp;
|
||||
struct gpio_chip *chip = &pctrl->chip;
|
||||
struct device *dev = pctrl->dev;
|
||||
bool need_valid_mask = !dmi_check_system(chv_no_valid_mask);
|
||||
int ret, i, irq_base;
|
||||
|
||||
*chip = chv_gpio_chip;
|
||||
|
||||
chip->ngpio = pctrl->soc->pins[pctrl->soc->npins - 1].number + 1;
|
||||
chip->label = dev_name(pctrl->dev);
|
||||
chip->label = dev_name(dev);
|
||||
chip->add_pin_ranges = chv_gpio_add_pin_ranges;
|
||||
chip->parent = pctrl->dev;
|
||||
chip->parent = dev;
|
||||
chip->base = -1;
|
||||
|
||||
pctrl->irq = irq;
|
||||
|
@ -1565,17 +1628,16 @@ static int chv_gpio_probe(struct intel_pinctrl *pctrl, int irq)
|
|||
if (need_valid_mask) {
|
||||
chip->irq.init_valid_mask = chv_init_irq_valid_mask;
|
||||
} else {
|
||||
irq_base = devm_irq_alloc_descs(pctrl->dev, -1, 0,
|
||||
pctrl->soc->npins, NUMA_NO_NODE);
|
||||
irq_base = devm_irq_alloc_descs(dev, -1, 0, pctrl->soc->npins, NUMA_NO_NODE);
|
||||
if (irq_base < 0) {
|
||||
dev_err(pctrl->dev, "Failed to allocate IRQ numbers\n");
|
||||
dev_err(dev, "Failed to allocate IRQ numbers\n");
|
||||
return irq_base;
|
||||
}
|
||||
}
|
||||
|
||||
ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
|
||||
ret = devm_gpiochip_add_data(dev, chip, pctrl);
|
||||
if (ret) {
|
||||
dev_err(pctrl->dev, "Failed to register gpiochip\n");
|
||||
dev_err(dev, "Failed to register gpiochip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1617,11 +1679,13 @@ static acpi_status chv_pinctrl_mmio_access_handler(u32 function,
|
|||
static int chv_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct intel_pinctrl_soc_data *soc_data;
|
||||
struct intel_community_context *cctx;
|
||||
struct intel_community *community;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
struct intel_pinctrl *pctrl;
|
||||
acpi_status status;
|
||||
unsigned int i;
|
||||
int ret, irq;
|
||||
|
||||
soc_data = intel_pinctrl_get_soc_data(pdev);
|
||||
|
@ -1663,6 +1727,10 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
|
|||
if (!pctrl->context.communities)
|
||||
return -ENOMEM;
|
||||
|
||||
cctx = &pctrl->context.communities[0];
|
||||
for (i = 0; i < ARRAY_SIZE(cctx->intr_lines); i++)
|
||||
cctx->intr_lines[i] = CHV_INVALID_HWIRQ;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
@ -1767,15 +1835,15 @@ static int chv_pinctrl_resume_noirq(struct device *dev)
|
|||
val &= ~CHV_PADCTRL0_GPIORXSTATE;
|
||||
if (ctx->padctrl0 != val) {
|
||||
chv_writel(pctrl, desc->number, CHV_PADCTRL0, ctx->padctrl0);
|
||||
dev_dbg(pctrl->dev, "restored pin %2u ctrl0 0x%08x\n",
|
||||
desc->number, chv_readl(pctrl, desc->number, CHV_PADCTRL0));
|
||||
dev_dbg(dev, "restored pin %2u ctrl0 0x%08x\n", desc->number,
|
||||
chv_readl(pctrl, desc->number, CHV_PADCTRL0));
|
||||
}
|
||||
|
||||
val = chv_readl(pctrl, desc->number, CHV_PADCTRL1);
|
||||
if (ctx->padctrl1 != val) {
|
||||
chv_writel(pctrl, desc->number, CHV_PADCTRL1, ctx->padctrl1);
|
||||
dev_dbg(pctrl->dev, "restored pin %2u ctrl1 0x%08x\n",
|
||||
desc->number, chv_readl(pctrl, desc->number, CHV_PADCTRL1));
|
||||
dev_dbg(dev, "restored pin %2u ctrl1 0x%08x\n", desc->number,
|
||||
chv_readl(pctrl, desc->number, CHV_PADCTRL1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue