ARM: pxa: fixes for v4.1-rc2

These fixes reenable the lubbock(pxa25x) and mainstone(pxa27x)
 platforms, which were broken since the gpio handling was
 converted to a driver, and the interrupt ordering broke the
 external interrupts of these systems.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJVQ13WAAoJEAP2et0duMsS98kP/2n5hHDdvIIC+ZSdhrNE/m4r
 R6f8xdmzx1701Q5vEXmYRh7TjgpvlZU1FQ5Im6kN8YidtEYWKuOdZOulKc/wDeS5
 +c2UlzF5RHdWSy2TwLFFLJ3fs6EmHl+GfisjJd5q9ht9GtwLonv8qNlOniQFvSTs
 i6XAKNoSLUDwZVzt4FxAhUud+bSiJBUP9bqhvT+ALeziTF7vd4rrRH2R21+zaHFB
 nQrWFDAkpEj0BT9PuxCNK/HZ5G5/+BH7k7MqGQpvRgVux0jzbJTIFsDTS6TPBMPT
 eM5TkWJCnW1/CvYn/clRIbT5BRJiAIOLt+2/4dt3a71/LDxhTw1/9xz0H9Fra87x
 U2giDIk3TFrgALLZoSqLY6n151baK2m6lf5UdjegCGAEQD2eIbhPos8VZ+zbvSjl
 BLarZSNFiBIau747jClYTSfjt4a626GaFbA49KASB/yKd/mi+V1td4DPLZ8LjCYB
 YSu9aQPS5OAVpYc2Xtc7qKwga+8DhKLlkmAQdXb+kCET4xI57geJ1abzNxTHAPbm
 qRUlWEigWUlkjlooY180h5/MCzosYeQ6cAYmStNxPVmhDZvL1ZicQBaVECZbIOIp
 G6aZwXoPEIKVJKO118tRUTrae6JdjMC1yCF5o5p7Wst4SOrgLOP6Fk/9YoeB+Qjb
 0wnq1eaBtpJ93MWlxF4r
 =bvjh
 -----END PGP SIGNATURE-----

Merge tag 'fixes-for-v4.1-rc2' of https://github.com/rjarzmik/linux into fixes

Merged "ARM: pxa: fixes for v4.1-rc2" from Robert Jarzmik:

These fixes reenable the lubbock(pxa25x) and mainstone(pxa27x)
platforms, which were broken since the gpio handling was
converted to a driver, and the interrupt ordering broke the
external interrupts of these systems.

* tag 'fixes-for-v4.1-rc2' of https://github.com/rjarzmik/linux:
  ARM: pxa: lubbock: use new pxa_cplds driver
  ARM: pxa: mainstone: use new pxa_cplds driver
  ARM: pxa: pxa_cplds: add lubbock and mainstone IO
This commit is contained in:
Arnd Bergmann 2015-05-07 18:23:00 +02:00
commit 1be518bd0b
7 changed files with 274 additions and 172 deletions

View File

@ -691,4 +691,13 @@ config SHARPSL_PM_MAX1111
config PXA310_ULPI
bool
config PXA_SYSTEMS_CPLDS
tristate "Motherboard cplds"
default ARCH_LUBBOCK || MACH_MAINSTONE
help
This driver supports the Lubbock and Mainstone multifunction chip
found on the pxa25x development platform system (Lubbock) and pxa27x
development platform system (Mainstone). This IO board supports the
interrupts handling, ethernet controller, flash chips, etc ...
endif

View File

@ -90,4 +90,5 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR) += raumfeld.o
obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o
obj-$(CONFIG_MACH_ZIPIT2) += z2.o
obj-$(CONFIG_PXA_SYSTEMS_CPLDS) += pxa_cplds_irqs.o
obj-$(CONFIG_TOSA_BT) += tosa-bt.o

View File

@ -37,7 +37,9 @@
#define LUB_GP __LUB_REG(LUBBOCK_FPGA_PHYS + 0x100)
/* Board specific IRQs */
#define LUBBOCK_IRQ(x) (IRQ_BOARD_START + (x))
#define LUBBOCK_NR_IRQS IRQ_BOARD_START
#define LUBBOCK_IRQ(x) (LUBBOCK_NR_IRQS + (x))
#define LUBBOCK_SD_IRQ LUBBOCK_IRQ(0)
#define LUBBOCK_SA1111_IRQ LUBBOCK_IRQ(1)
#define LUBBOCK_USB_IRQ LUBBOCK_IRQ(2) /* usb connect */
@ -47,8 +49,7 @@
#define LUBBOCK_USB_DISC_IRQ LUBBOCK_IRQ(6) /* usb disconnect */
#define LUBBOCK_LAST_IRQ LUBBOCK_IRQ(6)
#define LUBBOCK_SA1111_IRQ_BASE (IRQ_BOARD_START + 16)
#define LUBBOCK_NR_IRQS (IRQ_BOARD_START + 16 + 55)
#define LUBBOCK_SA1111_IRQ_BASE (LUBBOCK_NR_IRQS + 32)
#ifndef __ASSEMBLY__
extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set);

View File

@ -120,7 +120,9 @@
#define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */
/* board specific IRQs */
#define MAINSTONE_IRQ(x) (IRQ_BOARD_START + (x))
#define MAINSTONE_NR_IRQS IRQ_BOARD_START
#define MAINSTONE_IRQ(x) (MAINSTONE_NR_IRQS + (x))
#define MAINSTONE_MMC_IRQ MAINSTONE_IRQ(0)
#define MAINSTONE_USIM_IRQ MAINSTONE_IRQ(1)
#define MAINSTONE_USBC_IRQ MAINSTONE_IRQ(2)
@ -136,6 +138,4 @@
#define MAINSTONE_S1_STSCHG_IRQ MAINSTONE_IRQ(14)
#define MAINSTONE_S1_IRQ MAINSTONE_IRQ(15)
#define MAINSTONE_NR_IRQS (IRQ_BOARD_START + 16)
#endif

View File

@ -12,6 +12,7 @@
* published by the Free Software Foundation.
*/
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@ -123,84 +124,6 @@ void lubbock_set_misc_wr(unsigned int mask, unsigned int set)
}
EXPORT_SYMBOL(lubbock_set_misc_wr);
static unsigned long lubbock_irq_enabled;
static void lubbock_mask_irq(struct irq_data *d)
{
int lubbock_irq = (d->irq - LUBBOCK_IRQ(0));
LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq));
}
static void lubbock_unmask_irq(struct irq_data *d)
{
int lubbock_irq = (d->irq - LUBBOCK_IRQ(0));
/* the irq can be acknowledged only if deasserted, so it's done here */
LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq);
LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq));
}
static struct irq_chip lubbock_irq_chip = {
.name = "FPGA",
.irq_ack = lubbock_mask_irq,
.irq_mask = lubbock_mask_irq,
.irq_unmask = lubbock_unmask_irq,
};
static void lubbock_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
do {
/* clear our parent irq */
desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = LUBBOCK_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
}
pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
} while (pending);
}
static void __init lubbock_init_irq(void)
{
int irq;
pxa25x_init_irq();
/* setup extra lubbock irqs */
for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) {
irq_set_chip_and_handler(irq, &lubbock_irq_chip,
handle_level_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), lubbock_irq_handler);
irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING);
}
#ifdef CONFIG_PM
static void lubbock_irq_resume(void)
{
LUB_IRQ_MASK_EN = lubbock_irq_enabled;
}
static struct syscore_ops lubbock_irq_syscore_ops = {
.resume = lubbock_irq_resume,
};
static int __init lubbock_irq_device_init(void)
{
if (machine_is_lubbock()) {
register_syscore_ops(&lubbock_irq_syscore_ops);
return 0;
}
return -ENODEV;
}
device_initcall(lubbock_irq_device_init);
#endif
static int lubbock_udc_is_connected(void)
{
return (LUB_MISC_RD & (1 << 9)) == 0;
@ -383,11 +306,38 @@ static struct platform_device lubbock_flash_device[2] = {
},
};
static struct resource lubbock_cplds_resources[] = {
[0] = {
.start = LUBBOCK_FPGA_PHYS + 0xc0,
.end = LUBBOCK_FPGA_PHYS + 0xe0 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = PXA_GPIO_TO_IRQ(0),
.end = PXA_GPIO_TO_IRQ(0),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
},
[2] = {
.start = LUBBOCK_IRQ(0),
.end = LUBBOCK_IRQ(6),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device lubbock_cplds_device = {
.name = "pxa_cplds_irqs",
.id = -1,
.resource = &lubbock_cplds_resources[0],
.num_resources = 3,
};
static struct platform_device *devices[] __initdata = {
&sa1111_device,
&smc91x_device,
&lubbock_flash_device[0],
&lubbock_flash_device[1],
&lubbock_cplds_device,
};
static struct pxafb_mode_info sharp_lm8v31_mode = {
@ -648,7 +598,7 @@ MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
/* Maintainer: MontaVista Software Inc. */
.map_io = lubbock_map_io,
.nr_irqs = LUBBOCK_NR_IRQS,
.init_irq = lubbock_init_irq,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_time = pxa_timer_init,
.init_machine = lubbock_init,

View File

@ -13,6 +13,7 @@
* published by the Free Software Foundation.
*/
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
@ -122,92 +123,6 @@ static unsigned long mainstone_pin_config[] = {
GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
};
static unsigned long mainstone_irq_enabled;
static void mainstone_mask_irq(struct irq_data *d)
{
int mainstone_irq = (d->irq - MAINSTONE_IRQ(0));
MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq));
}
static void mainstone_unmask_irq(struct irq_data *d)
{
int mainstone_irq = (d->irq - MAINSTONE_IRQ(0));
/* the irq can be acknowledged only if deasserted, so it's done here */
MST_INTSETCLR &= ~(1 << mainstone_irq);
MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq));
}
static struct irq_chip mainstone_irq_chip = {
.name = "FPGA",
.irq_ack = mainstone_mask_irq,
.irq_mask = mainstone_mask_irq,
.irq_unmask = mainstone_unmask_irq,
};
static void mainstone_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled;
do {
/* clear useless edge notification */
desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = MAINSTONE_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
}
pending = MST_INTSETCLR & mainstone_irq_enabled;
} while (pending);
}
static void __init mainstone_init_irq(void)
{
int irq;
pxa27x_init_irq();
/* setup extra Mainstone irqs */
for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) {
irq_set_chip_and_handler(irq, &mainstone_irq_chip,
handle_level_irq);
if (irq == MAINSTONE_IRQ(10) || irq == MAINSTONE_IRQ(14))
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE | IRQF_NOAUTOEN);
else
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
set_irq_flags(MAINSTONE_IRQ(8), 0);
set_irq_flags(MAINSTONE_IRQ(12), 0);
MST_INTMSKENA = 0;
MST_INTSETCLR = 0;
irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), mainstone_irq_handler);
irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING);
}
#ifdef CONFIG_PM
static void mainstone_irq_resume(void)
{
MST_INTMSKENA = mainstone_irq_enabled;
}
static struct syscore_ops mainstone_irq_syscore_ops = {
.resume = mainstone_irq_resume,
};
static int __init mainstone_irq_device_init(void)
{
if (machine_is_mainstone())
register_syscore_ops(&mainstone_irq_syscore_ops);
return 0;
}
device_initcall(mainstone_irq_device_init);
#endif
static struct resource smc91x_resources[] = {
[0] = {
.start = (MST_ETH_PHYS + 0x300),
@ -487,11 +402,37 @@ static struct platform_device mst_gpio_keys_device = {
},
};
static struct resource mst_cplds_resources[] = {
[0] = {
.start = MST_FPGA_PHYS + 0xc0,
.end = MST_FPGA_PHYS + 0xe0 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = PXA_GPIO_TO_IRQ(0),
.end = PXA_GPIO_TO_IRQ(0),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
},
[2] = {
.start = MAINSTONE_IRQ(0),
.end = MAINSTONE_IRQ(15),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mst_cplds_device = {
.name = "pxa_cplds_irqs",
.id = -1,
.resource = &mst_cplds_resources[0],
.num_resources = 3,
};
static struct platform_device *platform_devices[] __initdata = {
&smc91x_device,
&mst_flash_device[0],
&mst_flash_device[1],
&mst_gpio_keys_device,
&mst_cplds_device,
};
static struct pxaohci_platform_data mainstone_ohci_platform_data = {
@ -718,7 +659,7 @@ MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
.atag_offset = 0x100, /* BLOB boot parameter setting */
.map_io = mainstone_map_io,
.nr_irqs = MAINSTONE_NR_IRQS,
.init_irq = mainstone_init_irq,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_time = pxa_timer_init,
.init_machine = mainstone_init,

View File

@ -0,0 +1,200 @@
/*
* Intel Reference Systems cplds
*
* Copyright (C) 2014 Robert Jarzmik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Cplds motherboard driver, supporting lubbock and mainstone SoC board.
*/
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#define FPGA_IRQ_MASK_EN 0x0
#define FPGA_IRQ_SET_CLR 0x10
#define CPLDS_NB_IRQ 32
struct cplds {
void __iomem *base;
int irq;
unsigned int irq_mask;
struct gpio_desc *gpio0;
struct irq_domain *irqdomain;
};
static irqreturn_t cplds_irq_handler(int in_irq, void *d)
{
struct cplds *fpga = d;
unsigned long pending;
unsigned int bit;
pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
for_each_set_bit(bit, &pending, CPLDS_NB_IRQ)
generic_handle_irq(irq_find_mapping(fpga->irqdomain, bit));
return IRQ_HANDLED;
}
static void cplds_irq_mask_ack(struct irq_data *d)
{
struct cplds *fpga = irq_data_get_irq_chip_data(d);
unsigned int cplds_irq = irqd_to_hwirq(d);
unsigned int set, bit = BIT(cplds_irq);
fpga->irq_mask &= ~bit;
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
set = readl(fpga->base + FPGA_IRQ_SET_CLR);
writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
}
static void cplds_irq_unmask(struct irq_data *d)
{
struct cplds *fpga = irq_data_get_irq_chip_data(d);
unsigned int cplds_irq = irqd_to_hwirq(d);
unsigned int bit = BIT(cplds_irq);
fpga->irq_mask |= bit;
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
}
static struct irq_chip cplds_irq_chip = {
.name = "pxa_cplds",
.irq_mask_ack = cplds_irq_mask_ack,
.irq_unmask = cplds_irq_unmask,
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
};
static int cplds_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq)
{
struct cplds *fpga = d->host_data;
irq_set_chip_and_handler(irq, &cplds_irq_chip, handle_level_irq);
irq_set_chip_data(irq, fpga);
return 0;
}
static const struct irq_domain_ops cplds_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
.map = cplds_irq_domain_map,
};
static int cplds_resume(struct platform_device *pdev)
{
struct cplds *fpga = platform_get_drvdata(pdev);
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
return 0;
}
static int cplds_probe(struct platform_device *pdev)
{
struct resource *res;
struct cplds *fpga;
int ret;
unsigned int base_irq = 0;
unsigned long irqflags = 0;
fpga = devm_kzalloc(&pdev->dev, sizeof(*fpga), GFP_KERNEL);
if (!fpga)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res) {
fpga->irq = (unsigned int)res->start;
irqflags = res->flags;
}
if (!fpga->irq)
return -ENODEV;
base_irq = platform_get_irq(pdev, 1);
if (base_irq < 0)
base_irq = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
fpga->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(fpga->base))
return PTR_ERR(fpga->base);
platform_set_drvdata(pdev, fpga);
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
writel(0, fpga->base + FPGA_IRQ_SET_CLR);
ret = devm_request_irq(&pdev->dev, fpga->irq, cplds_irq_handler,
irqflags, dev_name(&pdev->dev), fpga);
if (ret == -ENOSYS)
return -EPROBE_DEFER;
if (ret) {
dev_err(&pdev->dev, "couldn't request main irq%d: %d\n",
fpga->irq, ret);
return ret;
}
irq_set_irq_wake(fpga->irq, 1);
fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
CPLDS_NB_IRQ,
&cplds_irq_domain_ops, fpga);
if (!fpga->irqdomain)
return -ENODEV;
if (base_irq) {
ret = irq_create_strict_mappings(fpga->irqdomain, base_irq, 0,
CPLDS_NB_IRQ);
if (ret) {
dev_err(&pdev->dev, "couldn't create the irq mapping %d..%d\n",
base_irq, base_irq + CPLDS_NB_IRQ);
return ret;
}
}
return 0;
}
static int cplds_remove(struct platform_device *pdev)
{
struct cplds *fpga = platform_get_drvdata(pdev);
irq_set_chip_and_handler(fpga->irq, NULL, NULL);
return 0;
}
static const struct of_device_id cplds_id_table[] = {
{ .compatible = "intel,lubbock-cplds-irqs", },
{ .compatible = "intel,mainstone-cplds-irqs", },
{ }
};
MODULE_DEVICE_TABLE(of, cplds_id_table);
static struct platform_driver cplds_driver = {
.driver = {
.name = "pxa_cplds_irqs",
.of_match_table = of_match_ptr(cplds_id_table),
},
.probe = cplds_probe,
.remove = cplds_remove,
.resume = cplds_resume,
};
module_platform_driver(cplds_driver);
MODULE_DESCRIPTION("PXA Cplds interrupts driver");
MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
MODULE_LICENSE("GPL");