From 29c140b623ce2c55131c6d1c26a2f3e455723b81 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 3 Feb 2012 19:03:31 +0000 Subject: ARM: sa1111: fix memory request/grant setup on PM events We weren't re-enabling the memory request/grant signals on resume, causing DMA devices on the sa1111 to fail. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 61691cdbdcf..c7bed309b3a 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -87,7 +87,8 @@ #define IRQ_S0_BVD1_STSCHG (53) #define IRQ_S1_BVD1_STSCHG (54) -extern void __init sa1110_mb_enable(void); +extern void sa1110_mb_enable(void); +extern void sa1110_mb_disable(void); /* * We keep the following data for the overall SA1111. Note that the @@ -926,6 +927,10 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state) spin_unlock_irqrestore(&sachip->lock, flags); +#ifdef CONFIG_ARCH_SA1100 + sa1110_mb_disable(); +#endif + return 0; } @@ -966,6 +971,11 @@ static int sa1111_resume(struct platform_device *dev) */ sa1111_wake(sachip); +#ifdef CONFIG_ARCH_SA1100 + /* Enable the memory bus request/grant signals */ + sa1110_mb_enable(); +#endif + /* * Only lock for write ops. Also, sa1111_wake must be called with * released spinlock! -- cgit v1.2.3 From a22db0f38243f68957c89b1b9689a2064507bed6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 3 Feb 2012 19:05:13 +0000 Subject: ARM: sa1111: fix PWM state on suspend We should not write to the SA1111 registers after setting the SLEEP bit. Moreover, the manual says that the PWM registers should be disabled before we enter sleep. So, move the clearing of these registers earlier in the suspend sequence. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index c7bed309b3a..f0d9faadcc3 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -905,6 +905,9 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state) save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0); save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1); + sa1111_writel(0, sachip->base + SA1111_SKPWM0); + sa1111_writel(0, sachip->base + SA1111_SKPWM1); + base = sachip->base + SA1111_INTC; save->intpol0 = sa1111_readl(base + SA1111_INTPOL0); save->intpol1 = sa1111_readl(base + SA1111_INTPOL1); @@ -920,8 +923,6 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state) */ val = sa1111_readl(sachip->base + SA1111_SKCR); sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR); - sa1111_writel(0, sachip->base + SA1111_SKPWM0); - sa1111_writel(0, sachip->base + SA1111_SKPWM1); clk_disable(sachip->clk); -- cgit v1.2.3 From 4d5d11285c78691efb17148dfc3d56642bee6204 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 14 Jan 2012 16:09:22 +0000 Subject: ARM: sa1111: add sa1111 core driver .owner initializer Add an initializer for the struct device_driver .owner member. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index f0d9faadcc3..957f6e3c428 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -1064,6 +1064,7 @@ static struct platform_driver sa1111_device_driver = { .resume = sa1111_resume, .driver = { .name = "sa1111", + .owner = THIS_MODULE, }, }; -- cgit v1.2.3 From f03ecaa0aa3a3b74b9b9e8341cf7919516c902d5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 16 Jan 2012 00:09:22 +0000 Subject: ARM: sa1111: finish "allow cascaded IRQs to be used by platforms" Commit 19851c58e680 (sa1111: allow cascaded IRQs to be used by platforms) moved the IRQ definitions to the .c file, and added an irq_base member to the private data structure. The inerrupt demultiplexer uses irq_base, but the interrupt setup code does not. Also, although the commit adds a private data structure to pass this data, it isn't even referenced, resulting in irq_base being zero. We also copied the IRQ numbers from the device info array into the actual devices, resulting in wrong interrupt numbers passed to the sub-devices. The net effect of this is that we always overwrite IRQs 0-54, even if they are allocated elsewhere in the system. Add the code necessary to setup the private irq_base, and use it in the IRQ setup code. Make the SA-1111 probe fail with -EINVAL if there is no platform data provided. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 957f6e3c428..d3a8f5e2648 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -438,7 +438,7 @@ static struct irq_chip sa1111_high_chip = { static void sa1111_setup_irq(struct sa1111 *sachip) { void __iomem *irqbase = sachip->base + SA1111_INTC; - unsigned int irq; + unsigned i, irq; /* * We're guaranteed that this region hasn't been taken. @@ -464,14 +464,16 @@ static void sa1111_setup_irq(struct sa1111 *sachip) sa1111_writel(~0, irqbase + SA1111_INTSTATCLR0); sa1111_writel(~0, irqbase + SA1111_INTSTATCLR1); - for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { + for (i = IRQ_GPAIN0; i <= SSPROR; i++) { + irq = sachip->irq_base + i; irq_set_chip_and_handler(irq, &sa1111_low_chip, handle_edge_irq); irq_set_chip_data(irq, sachip); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) { + for (i = AUDXMTDMADONEA; i <= IRQ_S1_BVD1_STSCHG; i++) { + irq = sachip->irq_base + i; irq_set_chip_and_handler(irq, &sa1111_high_chip, handle_edge_irq); irq_set_chip_data(irq, sachip); @@ -625,6 +627,7 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, struct sa1111_dev_info *info) { struct sa1111_dev *dev; + unsigned i; int ret; dev = kzalloc(sizeof(struct sa1111_dev), GFP_KERNEL); @@ -645,7 +648,9 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->res.flags = IORESOURCE_MEM; dev->mapbase = sachip->base + info->offset; dev->skpcr_mask = info->skpcr_mask; - memmove(dev->irq, info->irq, sizeof(dev->irq)); + + for (i = 0; i < ARRAY_SIZE(info->irq); i++) + dev->irq[i] = sachip->irq_base + info->irq[i]; ret = request_resource(parent, &dev->res); if (ret) { @@ -699,16 +704,21 @@ out: * Returns: * %-ENODEV device not found. * %-EBUSY physical address already marked in-use. + * %-EINVAL no platform data passed * %0 successful. */ static int __devinit __sa1111_probe(struct device *me, struct resource *mem, int irq) { + struct sa1111_platform_data *pd = me->platform_data; struct sa1111 *sachip; unsigned long id; unsigned int has_devs; int i, ret = -ENODEV; + if (!pd) + return -EINVAL; + sachip = kzalloc(sizeof(struct sa1111), GFP_KERNEL); if (!sachip) return -ENOMEM; @@ -730,6 +740,7 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) sachip->phys = mem->start; sachip->irq = irq; + sachip->irq_base = pd->irq_base; /* * Map the whole region. This also maps the -- cgit v1.2.3 From 36d312130228504a223de44739c807b0353248c1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 24 Jan 2012 21:25:20 +0000 Subject: ARM: sa1111: implement support for sparse IRQs Implement the necessary allocation/freeing functionality to support sparse IRQs with the SA-1111 device. On non-sparse IRQ platforms, this allows us to dynamically allocate from within the available IRQ number space. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index d3a8f5e2648..b64a3360c8c 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -16,6 +16,7 @@ */ #include #include +#include #include #include #include @@ -28,9 +29,8 @@ #include #include -#include -#include #include +#include #include #include @@ -86,6 +86,7 @@ #define IRQ_S1_CD_VALID (52) #define IRQ_S0_BVD1_STSCHG (53) #define IRQ_S1_BVD1_STSCHG (54) +#define SA1111_IRQ_NR (55) extern void sa1110_mb_enable(void); extern void sa1110_mb_disable(void); @@ -435,16 +436,28 @@ static struct irq_chip sa1111_high_chip = { .irq_set_wake = sa1111_wake_highirq, }; -static void sa1111_setup_irq(struct sa1111 *sachip) +static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base) { void __iomem *irqbase = sachip->base + SA1111_INTC; unsigned i, irq; + int ret; /* * We're guaranteed that this region hasn't been taken. */ request_mem_region(sachip->phys + SA1111_INTC, 512, "irq"); + ret = irq_alloc_descs(-1, irq_base, SA1111_IRQ_NR, -1); + if (ret <= 0) { + dev_err(sachip->dev, "unable to allocate %u irqs: %d\n", + SA1111_IRQ_NR, ret); + if (ret == 0) + ret = -EINVAL; + return ret; + } + + sachip->irq_base = ret; + /* disable all IRQs */ sa1111_writel(0, irqbase + SA1111_INTEN0); sa1111_writel(0, irqbase + SA1111_INTEN1); @@ -486,6 +499,11 @@ static void sa1111_setup_irq(struct sa1111 *sachip) irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING); irq_set_handler_data(sachip->irq, sachip); irq_set_chained_handler(sachip->irq, sa1111_irq_handler); + + dev_info(sachip->dev, "Providing IRQ%u-%u\n", + sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1); + + return 0; } /* @@ -740,7 +758,6 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) sachip->phys = mem->start; sachip->irq = irq; - sachip->irq_base = pd->irq_base; /* * Map the whole region. This also maps the @@ -771,6 +788,16 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) */ sa1111_wake(sachip); + /* + * The interrupt controller must be initialised before any + * other device to ensure that the interrupts are available. + */ + if (sachip->irq != NO_IRQ) { + ret = sa1111_setup_irq(sachip, pd->irq_base); + if (ret) + goto err_unmap; + } + #ifdef CONFIG_ARCH_SA1100 { unsigned int val; @@ -801,13 +828,6 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) } #endif - /* - * The interrupt controller must be initialised before any - * other device to ensure that the interrupts are available. - */ - if (sachip->irq != NO_IRQ) - sa1111_setup_irq(sachip); - g_sa1111 = sachip; has_devs = ~0; @@ -858,6 +878,7 @@ static void __sa1111_remove(struct sa1111 *sachip) if (sachip->irq != NO_IRQ) { irq_set_chained_handler(sachip->irq, NULL); irq_set_handler_data(sachip->irq, NULL); + irq_free_descs(sachip->irq_base, SA1111_IRQ_NR); release_mem_region(sachip->phys + SA1111_INTC, 512); } -- cgit v1.2.3 From 6bd72f0562142ddae26a052cfc4e578ad6953d06 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Jan 2012 11:01:18 +0000 Subject: ARM: sa1111: add shutdown hook to sa1111_driver structure Add a shutdown hook to the sa1111_driver structure to allow drivers to be notified of system reboots and shutdowns. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 9 +++++++++ arch/arm/include/asm/hardware/sa1111.h | 1 + 2 files changed, 10 insertions(+) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index b64a3360c8c..b0f93628dcd 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -1348,6 +1348,14 @@ static int sa1111_bus_resume(struct device *dev) return ret; } +static void sa1111_bus_shutdown(struct device *dev) +{ + struct sa1111_driver *drv = SA1111_DRV(dev->driver); + + if (drv && drv->shutdown) + drv->shutdown(SA1111_DEV(dev)); +} + static int sa1111_bus_probe(struct device *dev) { struct sa1111_dev *sadev = SA1111_DEV(dev); @@ -1377,6 +1385,7 @@ struct bus_type sa1111_bus_type = { .remove = sa1111_bus_remove, .suspend = sa1111_bus_suspend, .resume = sa1111_bus_resume, + .shutdown = sa1111_bus_shutdown, }; EXPORT_SYMBOL(sa1111_bus_type); diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h index 92ed254c175..29e320f6f85 100644 --- a/arch/arm/include/asm/hardware/sa1111.h +++ b/arch/arm/include/asm/hardware/sa1111.h @@ -548,6 +548,7 @@ struct sa1111_driver { int (*remove)(struct sa1111_dev *); int (*suspend)(struct sa1111_dev *, pm_message_t); int (*resume)(struct sa1111_dev *); + void (*shutdown)(struct sa1111_dev *); }; #define SA1111_DRV(_d) container_of((_d), struct sa1111_driver, drv) -- cgit v1.2.3 From ae99ddbc976572194e8a68cb9ca1e27805ce30c7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Jan 2012 13:25:47 +0000 Subject: ARM: sa1111: add platform enable/disable functions Add platform hooks to be called when individual sa1111 devices are enabled and disabled. This will allow us to move some platform specifics out of the individual drivers. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 22 +++++++++++++++++----- arch/arm/include/asm/hardware/sa1111.h | 8 ++++++-- drivers/input/serio/sa1111ps2.c | 6 +++++- drivers/pcmcia/sa1111_generic.c | 11 +++++++++-- drivers/usb/host/ohci-sa1111.c | 19 ++++++++++++++----- 5 files changed, 51 insertions(+), 15 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index b0f93628dcd..1366e82e670 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -106,6 +106,7 @@ struct sa1111 { int irq_base; /* base for cascaded on-chip IRQs */ spinlock_t lock; void __iomem *base; + struct sa1111_platform_data *pdata; #ifdef CONFIG_PM void *saved_state; #endif @@ -756,6 +757,7 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) sachip->dev = me; dev_set_drvdata(sachip->dev, sachip); + sachip->pdata = pd; sachip->phys = mem->start; sachip->irq = irq; @@ -1282,16 +1284,23 @@ EXPORT_SYMBOL(sa1111_set_sleep_io); * sa1111_enable_device - enable an on-chip SA1111 function block * @sadev: SA1111 function block device to enable */ -void sa1111_enable_device(struct sa1111_dev *sadev) +int sa1111_enable_device(struct sa1111_dev *sadev) { struct sa1111 *sachip = sa1111_chip_driver(sadev); unsigned long flags; unsigned int val; + int ret = 0; - spin_lock_irqsave(&sachip->lock, flags); - val = sa1111_readl(sachip->base + SA1111_SKPCR); - sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); - spin_unlock_irqrestore(&sachip->lock, flags); + if (sachip->pdata && sachip->pdata->enable) + ret = sachip->pdata->enable(sachip->pdata->data, sadev->devid); + + if (ret == 0) { + spin_lock_irqsave(&sachip->lock, flags); + val = sa1111_readl(sachip->base + SA1111_SKPCR); + sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); + spin_unlock_irqrestore(&sachip->lock, flags); + } + return ret; } EXPORT_SYMBOL(sa1111_enable_device); @@ -1309,6 +1318,9 @@ void sa1111_disable_device(struct sa1111_dev *sadev) val = sa1111_readl(sachip->base + SA1111_SKPCR); sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR); spin_unlock_irqrestore(&sachip->lock, flags); + + if (sachip->pdata && sachip->pdata->disable) + sachip->pdata->disable(sachip->pdata->data, sadev->devid); } EXPORT_SYMBOL(sa1111_disable_device); diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h index 29e320f6f85..d54d781021c 100644 --- a/arch/arm/include/asm/hardware/sa1111.h +++ b/arch/arm/include/asm/hardware/sa1111.h @@ -556,9 +556,10 @@ struct sa1111_driver { #define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name) /* - * These frob the SKPCR register. + * These frob the SKPCR register, and call platform specific + * enable/disable functions. */ -void sa1111_enable_device(struct sa1111_dev *); +int sa1111_enable_device(struct sa1111_dev *); void sa1111_disable_device(struct sa1111_dev *); unsigned int sa1111_pll_clock(struct sa1111_dev *); @@ -581,6 +582,9 @@ void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned i struct sa1111_platform_data { int irq_base; /* base for cascaded on-chip IRQs */ + void *data; + int (*enable)(void *, unsigned); + void (*disable)(void *, unsigned); }; #endif /* _ASM_ARCH_SA1111 */ diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 40ec545fbd4..ad7d23b5c6f 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -124,13 +124,16 @@ static int ps2_open(struct serio *io) struct ps2if *ps2if = io->port_data; int ret; - sa1111_enable_device(ps2if->dev); + ret = sa1111_enable_device(ps2if->dev); + if (ret) + return ret; ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0, SA1111_DRIVER_NAME(ps2if->dev), ps2if); if (ret) { printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", ps2if->dev->irq[0], ret); + sa1111_disable_device(ps2if->dev); return ret; } @@ -140,6 +143,7 @@ static int ps2_open(struct serio *io) printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", ps2if->dev->irq[1], ret); free_irq(ps2if->dev->irq[0], ps2if); + sa1111_disable_device(ps2if->dev); return ret; } diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index 27f2fe3b7fb..0735c3e6a8b 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -163,12 +163,18 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, static int pcmcia_probe(struct sa1111_dev *dev) { void __iomem *base; + int ret; + + ret = sa1111_enable_device(dev); + if (ret) + return ret; dev_set_drvdata(&dev->dev, NULL); - if (!request_mem_region(dev->res.start, 512, - SA1111_DRIVER_NAME(dev))) + if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) { + sa1111_disable_device(dev); return -EBUSY; + } base = dev->mapbase; @@ -212,6 +218,7 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev) } release_mem_region(dev->res.start, 512); + sa1111_disable_device(dev); return 0; } diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 7d2aa62ea61..f61f4f90529 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -27,9 +27,10 @@ extern int usb_disabled(void); /*-------------------------------------------------------------------------*/ -static void sa1111_start_hc(struct sa1111_dev *dev) +static int sa1111_start_hc(struct sa1111_dev *dev) { unsigned int usb_rst = 0; + int ret; printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n", __FILE__); @@ -57,9 +58,13 @@ static void sa1111_start_hc(struct sa1111_dev *dev) * Now, carefully enable the USB clock, and take * the USB host controller out of reset. */ - sa1111_enable_device(dev); - udelay(11); - sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET); + ret = sa1111_enable_device(dev); + if (ret == 0) { + udelay(11); + sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET); + } + + return ret; } static void sa1111_stop_hc(struct sa1111_dev *dev) @@ -140,7 +145,10 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, } hcd->regs = dev->mapbase; - sa1111_start_hc(dev); + ret = sa1111_start_hc(dev); + if (ret) + goto err2; + ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, dev->irq[1], 0); @@ -148,6 +156,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, return retval; sa1111_stop_hc(dev); + err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); -- cgit v1.2.3 From e5c0fc4185c551c270868dcb6573604db2bc3171 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 25 Jan 2012 10:42:52 +0000 Subject: ARM: sa1111: change devid to be a bitmask Change the sa1111 device id to be a bitmask. This allows us to specify the actual device, while allowing a single driver to bind to both PS2 devices. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 12 ++++++------ arch/arm/include/asm/hardware/sa1111.h | 20 +++++++++++--------- 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 1366e82e670..4bdf1bb283d 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -158,7 +158,7 @@ static struct sa1111_dev_info sa1111_devices[] = { { .offset = SA1111_KBD, .skpcr_mask = SKPCR_PTCLKEN, - .devid = SA1111_DEVID_PS2, + .devid = SA1111_DEVID_PS2_KBD, .irq = { IRQ_TPRXINT, IRQ_TPTXINT @@ -167,7 +167,7 @@ static struct sa1111_dev_info sa1111_devices[] = { { .offset = SA1111_MSE, .skpcr_mask = SKPCR_PMCLKEN, - .devid = SA1111_DEVID_PS2, + .devid = SA1111_DEVID_PS2_MSE, .irq = { IRQ_MSRXINT, IRQ_MSTXINT @@ -835,12 +835,12 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) has_devs = ~0; if (machine_is_assabet() || machine_is_jornada720() || machine_is_badge4()) - has_devs &= ~(1 << 4); + has_devs &= ~SA1111_DEVID_PS2_MSE; else - has_devs &= ~(1 << 1); + has_devs &= ~SA1111_DEVID_SAC; for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++) - if (has_devs & (1 << i)) + if (sa1111_devices[i].devid & has_devs) sa1111_init_one_child(sachip, mem, &sa1111_devices[i]); return 0; @@ -1335,7 +1335,7 @@ static int sa1111_match(struct device *_dev, struct device_driver *_drv) struct sa1111_dev *dev = SA1111_DEV(_dev); struct sa1111_driver *drv = SA1111_DRV(_drv); - return dev->devid == drv->devid; + return dev->devid & drv->devid; } static int sa1111_bus_suspend(struct device *dev, pm_message_t state) diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h index d54d781021c..37ad29d482f 100644 --- a/arch/arm/include/asm/hardware/sa1111.h +++ b/arch/arm/include/asm/hardware/sa1111.h @@ -516,15 +516,17 @@ extern struct bus_type sa1111_bus_type; -#define SA1111_DEVID_SBI 0 -#define SA1111_DEVID_SK 1 -#define SA1111_DEVID_USB 2 -#define SA1111_DEVID_SAC 3 -#define SA1111_DEVID_SSP 4 -#define SA1111_DEVID_PS2 5 -#define SA1111_DEVID_GPIO 6 -#define SA1111_DEVID_INT 7 -#define SA1111_DEVID_PCMCIA 8 +#define SA1111_DEVID_SBI (1 << 0) +#define SA1111_DEVID_SK (1 << 1) +#define SA1111_DEVID_USB (1 << 2) +#define SA1111_DEVID_SAC (1 << 3) +#define SA1111_DEVID_SSP (1 << 4) +#define SA1111_DEVID_PS2 (3 << 5) +#define SA1111_DEVID_PS2_KBD (1 << 5) +#define SA1111_DEVID_PS2_MSE (1 << 6) +#define SA1111_DEVID_GPIO (1 << 7) +#define SA1111_DEVID_INT (1 << 8) +#define SA1111_DEVID_PCMCIA (1 << 9) struct sa1111_dev { struct device dev; -- cgit v1.2.3 From 07be45f57ebe037977c8033a008e9012617b1915 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Jan 2012 13:34:21 +0000 Subject: ARM: sa1111: provide a generic way to prevent devices from registering Some platforms don't want certain devices to be registered, because, eg, the interface is not wired. Provide a way for platforms to prevent various devices from being registered via a devid bitmask in the platform data. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 7 ++----- arch/arm/include/asm/hardware/sa1111.h | 1 + arch/arm/mach-pxa/lubbock.c | 1 + arch/arm/mach-sa1100/badge4.c | 1 + arch/arm/mach-sa1100/jornada720.c | 1 + arch/arm/mach-sa1100/neponset.c | 1 + 6 files changed, 7 insertions(+), 5 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 4bdf1bb283d..17694cf64aa 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -833,11 +833,8 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) g_sa1111 = sachip; has_devs = ~0; - if (machine_is_assabet() || machine_is_jornada720() || - machine_is_badge4()) - has_devs &= ~SA1111_DEVID_PS2_MSE; - else - has_devs &= ~SA1111_DEVID_SAC; + if (pd) + has_devs &= ~pd->disable_devs; for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++) if (sa1111_devices[i].devid & has_devs) diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h index 37ad29d482f..74afe20ffff 100644 --- a/arch/arm/include/asm/hardware/sa1111.h +++ b/arch/arm/include/asm/hardware/sa1111.h @@ -584,6 +584,7 @@ void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned i struct sa1111_platform_data { int irq_base; /* base for cascaded on-chip IRQs */ + unsigned disable_devs; void *data; int (*enable)(void *, unsigned); void (*disable)(void *, unsigned); diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 6ebd276aebe..6bb3f47b1f1 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -223,6 +223,7 @@ static struct resource sa1111_resources[] = { static struct sa1111_platform_data sa1111_info = { .irq_base = LUBBOCK_SA1111_IRQ_BASE, + .disable_devs = SA1111_DEVID_SAC, }; static struct platform_device sa1111_device = { diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c index d84924993ba..8fb80f02c2a 100644 --- a/arch/arm/mach-sa1100/badge4.c +++ b/arch/arm/mach-sa1100/badge4.c @@ -66,6 +66,7 @@ static void badge4_sa1111_disable(void *data, unsigned devid) static struct sa1111_platform_data sa1111_info = { .irq_base = IRQ_BOARD_END, + .disable_devs = SA1111_DEVID_PS2_MSE, .enable = badge4_sa1111_enable, .disable = badge4_sa1111_disable, }; diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index ee121d6f048..dcd6d026aa6 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -211,6 +211,7 @@ static struct resource sa1111_resources[] = { static struct sa1111_platform_data sa1111_info = { .irq_base = IRQ_BOARD_END, + .disable_devs = SA1111_DEVID_PS2_MSE, }; static u64 sa1111_dmamask = 0xffffffffUL; diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index b4fa53a1427..b40a7192f09 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -242,6 +242,7 @@ static struct resource sa1111_resources[] = { static struct sa1111_platform_data sa1111_info = { .irq_base = IRQ_BOARD_END, + .disable_devs = SA1111_DEVID_PS2_MSE, }; static u64 sa1111_dmamask = 0xffffffffUL; -- cgit v1.2.3 From 09a2ba2fa0eba3da747db860ac1c8c0956665316 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 29 Jan 2012 09:31:31 +0000 Subject: ARM: sa1111: register sa1111 devices with dmabounce in bus notifier Use the bus notifier to register sa1111 devices with dmabounce, rather than after the device has been registered, potentially racing with driver binding. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 129 +++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 55 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 17694cf64aa..7b4351b28a5 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -603,36 +603,6 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, } #endif -#ifdef CONFIG_DMABOUNCE -/* - * According to the "Intel StrongARM SA-1111 Microprocessor Companion - * Chip Specification Update" (June 2000), erratum #7, there is a - * significant bug in the SA1111 SDRAM shared memory controller. If - * an access to a region of memory above 1MB relative to the bank base, - * it is important that address bit 10 _NOT_ be asserted. Depending - * on the configuration of the RAM, bit 10 may correspond to one - * of several different (processor-relative) address bits. - * - * This routine only identifies whether or not a given DMA address - * is susceptible to the bug. - * - * This should only get called for sa1111_device types due to the - * way we configure our device dma_masks. - */ -static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) -{ - /* - * Section 4.6 of the "Intel StrongARM SA-1111 Development Module - * User's Guide" mentions that jumpers R51 and R52 control the - * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or - * SDRAM bank 1 on Neponset). The default configuration selects - * Assabet, so any address in bank 1 is necessarily invalid. - */ - return (machine_is_assabet() || machine_is_pfs168()) && - (addr >= 0xc8000000 || (addr + size) >= 0xc8000000); -} -#endif - static void sa1111_dev_release(struct device *_dev) { struct sa1111_dev *dev = SA1111_DEV(_dev); @@ -660,7 +630,6 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->dev.parent = sachip->dev; dev->dev.bus = &sa1111_bus_type; dev->dev.release = sa1111_dev_release; - dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask; dev->res.start = sachip->phys + info->offset; dev->res.end = dev->res.start + 511; dev->res.name = dev_name(&dev->dev); @@ -671,6 +640,16 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, for (i = 0; i < ARRAY_SIZE(info->irq); i++) dev->irq[i] = sachip->irq_base + info->irq[i]; + /* + * If the parent device has a DMA mask associated with it, + * propagate it down to the children. + */ + if (sachip->dev->dma_mask) { + dev->dma_mask = *sachip->dev->dma_mask; + dev->dev.dma_mask = &dev->dma_mask; + dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask; + } + ret = request_resource(parent, &dev->res); if (ret) { printk("SA1111: failed to allocate resource for %s\n", @@ -680,36 +659,12 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, goto out; } - ret = device_register(&dev->dev); if (ret) { release_resource(&dev->res); kfree(dev); - goto out; - } - -#ifdef CONFIG_DMABOUNCE - /* - * If the parent device has a DMA mask associated with it, - * propagate it down to the children. - */ - if (sachip->dev->dma_mask) { - dev->dma_mask = *sachip->dev->dma_mask; - dev->dev.dma_mask = &dev->dma_mask; - - if (dev->dma_mask != 0xffffffffUL) { - ret = dmabounce_register_dev(&dev->dev, 1024, 4096, - sa1111_needs_bounce); - if (ret) { - dev_err(&dev->dev, "SA1111: Failed to register" - " with dmabounce\n"); - device_unregister(&dev->dev); - } - } } -#endif -out: return ret; } @@ -1411,9 +1366,70 @@ void sa1111_driver_unregister(struct sa1111_driver *driver) } EXPORT_SYMBOL(sa1111_driver_unregister); +#ifdef CONFIG_DMABOUNCE +/* + * According to the "Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update" (June 2000), erratum #7, there is a + * significant bug in the SA1111 SDRAM shared memory controller. If + * an access to a region of memory above 1MB relative to the bank base, + * it is important that address bit 10 _NOT_ be asserted. Depending + * on the configuration of the RAM, bit 10 may correspond to one + * of several different (processor-relative) address bits. + * + * This routine only identifies whether or not a given DMA address + * is susceptible to the bug. + * + * This should only get called for sa1111_device types due to the + * way we configure our device dma_masks. + */ +static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) +{ + /* + * Section 4.6 of the "Intel StrongARM SA-1111 Development Module + * User's Guide" mentions that jumpers R51 and R52 control the + * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or + * SDRAM bank 1 on Neponset). The default configuration selects + * Assabet, so any address in bank 1 is necessarily invalid. + */ + return (machine_is_assabet() || machine_is_pfs168()) && + (addr >= 0xc8000000 || (addr + size) >= 0xc8000000); +} + +static int sa1111_notifier_call(struct notifier_block *n, unsigned long action, + void *data) +{ + struct sa1111_dev *dev = SA1111_DEV(data); + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL) { + int ret = dmabounce_register_dev(&dev->dev, 1024, 4096, + sa1111_needs_bounce); + if (ret) + dev_err(&dev->dev, "failed to register with dmabounce: %d\n", ret); + } + break; + + case BUS_NOTIFY_DEL_DEVICE: + if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL) + dmabounce_unregister_dev(&dev->dev); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block sa1111_bus_notifier = { + .notifier_call = sa1111_notifier_call, +}; +#endif + static int __init sa1111_init(void) { int ret = bus_register(&sa1111_bus_type); +#ifdef CONFIG_DMABOUNCE + if (ret == 0) + bus_register_notifier(&sa1111_bus_type, &sa1111_bus_notifier); +#endif if (ret == 0) platform_driver_register(&sa1111_device_driver); return ret; @@ -1422,6 +1438,9 @@ static int __init sa1111_init(void) static void __exit sa1111_exit(void) { platform_driver_unregister(&sa1111_device_driver); +#ifdef CONFIG_DMABOUNCE + bus_unregister_notifier(&sa1111_bus_type, &sa1111_bus_notifier); +#endif bus_unregister(&sa1111_bus_type); } -- cgit v1.2.3 From 21d1c7702e74337717a1133fe8665f6591768581 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 29 Jan 2012 10:22:49 +0000 Subject: ARM: sa1111: only setup DMA for DMA capable devices It's pointless registering the PS/2 interfaces with the dmabounce code when there's no DMA support for these in hardware, so only setup the DMA masks for two subdevices which support DMA - the OHCI and SAC. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 7b4351b28a5..d78499f84bd 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -121,6 +121,7 @@ static struct sa1111 *g_sa1111; struct sa1111_dev_info { unsigned long offset; unsigned long skpcr_mask; + bool dma; unsigned int devid; unsigned int irq[6]; }; @@ -129,6 +130,7 @@ static struct sa1111_dev_info sa1111_devices[] = { { .offset = SA1111_USB, .skpcr_mask = SKPCR_UCLKEN, + .dma = true, .devid = SA1111_DEVID_USB, .irq = { IRQ_USBPWR, @@ -142,6 +144,7 @@ static struct sa1111_dev_info sa1111_devices[] = { { .offset = 0x0600, .skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN, + .dma = true, .devid = SA1111_DEVID_SAC, .irq = { AUDXMTDMADONEA, @@ -641,10 +644,10 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->irq[i] = sachip->irq_base + info->irq[i]; /* - * If the parent device has a DMA mask associated with it, - * propagate it down to the children. + * If the parent device has a DMA mask associated with it, and + * this child supports DMA, propagate it down to the children. */ - if (sachip->dev->dma_mask) { + if (info->dma && sachip->dev->dma_mask) { dev->dma_mask = *sachip->dev->dma_mask; dev->dev.dma_mask = &dev->dma_mask; dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask; -- cgit v1.2.3 From 924e1d4910a1f7d53f949a92a5d7793e572bb21d Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 29 Jan 2012 10:20:00 +0000 Subject: ARM: sa1111: cleanup sub-device registration and unregistration Move the releasing of resources out of the release function - this allows a cleaner and more conventional arrangement of the registration failure paths and a saner unregistration process for these devices. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index d78499f84bd..8d86338a54c 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -610,7 +610,6 @@ static void sa1111_dev_release(struct device *_dev) { struct sa1111_dev *dev = SA1111_DEV(_dev); - release_resource(&dev->res); kfree(dev); } @@ -625,9 +624,10 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev = kzalloc(sizeof(struct sa1111_dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; - goto out; + goto err_alloc; } + device_initialize(&dev->dev); dev_set_name(&dev->dev, "%4.4lx", info->offset); dev->devid = info->devid; dev->dev.parent = sachip->dev; @@ -657,17 +657,19 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, if (ret) { printk("SA1111: failed to allocate resource for %s\n", dev->res.name); - dev_set_name(&dev->dev, NULL); - kfree(dev); - goto out; + goto err_resource; } - ret = device_register(&dev->dev); - if (ret) { - release_resource(&dev->res); - kfree(dev); - } + ret = device_add(&dev->dev); + if (ret) + goto err_add; + return 0; + err_add: + release_resource(&dev->res); + err_resource: + put_device(&dev->dev); + err_alloc: return ret; } @@ -813,7 +815,10 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) static int sa1111_remove_one(struct device *dev, void *data) { - device_unregister(dev); + struct sa1111_dev *sadev = SA1111_DEV(dev); + device_del(&sadev->dev); + release_resource(&sadev->res); + put_device(&sadev->dev); return 0; } -- cgit v1.2.3 From 22eeaff367ac85a09643b2b8a5af064ec8773f63 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 29 Jan 2012 10:28:09 +0000 Subject: ARM: sa1111: use dev_err() rather than printk() Use dev_err() to report device specific errors rather than printk(). Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 8d86338a54c..9173d112ea0 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -655,7 +655,7 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, ret = request_resource(parent, &dev->res); if (ret) { - printk("SA1111: failed to allocate resource for %s\n", + dev_err(sachip->dev, "failed to allocate resource for %s\n", dev->res.name); goto err_resource; } -- cgit v1.2.3