diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/pata_arasan_cf.c | 37 | ||||
-rw-r--r-- | drivers/clocksource/Kconfig | 1 | ||||
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 33 | ||||
-rw-r--r-- | drivers/clocksource/exynos_mct.c | 1 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-armada-370-xp.c | 288 | ||||
-rw-r--r-- | drivers/spi/spi-pl022.c | 43 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 64 |
8 files changed, 403 insertions, 65 deletions
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 405022d302c..7638121cb5d 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -209,8 +209,6 @@ struct arasan_cf_dev { struct dma_chan *dma_chan; /* Mask for DMA transfers */ dma_cap_mask_t mask; - /* dma channel private data */ - void *dma_priv; /* DMA transfer work */ struct work_struct work; /* DMA delayed finish work */ @@ -308,6 +306,7 @@ static void cf_card_detect(struct arasan_cf_dev *acdev, bool hotplugged) static int cf_init(struct arasan_cf_dev *acdev) { struct arasan_cf_pdata *pdata = dev_get_platdata(acdev->host->dev); + unsigned int if_clk; unsigned long flags; int ret = 0; @@ -325,8 +324,12 @@ static int cf_init(struct arasan_cf_dev *acdev) spin_lock_irqsave(&acdev->host->lock, flags); /* configure CF interface clock */ - writel((pdata->cf_if_clk <= CF_IF_CLK_200M) ? pdata->cf_if_clk : - CF_IF_CLK_166M, acdev->vbase + CLK_CFG); + /* TODO: read from device tree */ + if_clk = CF_IF_CLK_166M; + if (pdata && pdata->cf_if_clk <= CF_IF_CLK_200M) + if_clk = pdata->cf_if_clk; + + writel(if_clk, acdev->vbase + CLK_CFG); writel(TRUE_IDE_MODE | CFHOST_ENB, acdev->vbase + OP_MODE); cf_interrupt_enable(acdev, CARD_DETECT_IRQ, 1); @@ -357,12 +360,6 @@ static void dma_callback(void *dev) complete(&acdev->dma_completion); } -static bool filter(struct dma_chan *chan, void *slave) -{ - chan->private = slave; - return true; -} - static inline void dma_complete(struct arasan_cf_dev *acdev) { struct ata_queued_cmd *qc = acdev->qc; @@ -530,8 +527,7 @@ static void data_xfer(struct work_struct *work) /* request dma channels */ /* dma_request_channel may sleep, so calling from process context */ - acdev->dma_chan = dma_request_channel(acdev->mask, filter, - acdev->dma_priv); + acdev->dma_chan = dma_request_slave_channel(acdev->host->dev, "data"); if (!acdev->dma_chan) { dev_err(acdev->host->dev, "Unable to get dma_chan\n"); goto chan_request_fail; @@ -798,6 +794,7 @@ static int arasan_cf_probe(struct platform_device *pdev) struct ata_host *host; struct ata_port *ap; struct resource *res; + u32 quirk; irq_handler_t irq_handler = NULL; int ret = 0; @@ -817,12 +814,17 @@ static int arasan_cf_probe(struct platform_device *pdev) return -ENOMEM; } + if (pdata) + quirk = pdata->quirk; + else + quirk = CF_BROKEN_UDMA; /* as it is on spear1340 */ + /* if irq is 0, support only PIO */ acdev->irq = platform_get_irq(pdev, 0); if (acdev->irq) irq_handler = arasan_cf_interrupt; else - pdata->quirk |= CF_BROKEN_MWDMA | CF_BROKEN_UDMA; + quirk |= CF_BROKEN_MWDMA | CF_BROKEN_UDMA; acdev->pbase = res->start; acdev->vbase = devm_ioremap_nocache(&pdev->dev, res->start, @@ -859,17 +861,16 @@ static int arasan_cf_probe(struct platform_device *pdev) INIT_WORK(&acdev->work, data_xfer); INIT_DELAYED_WORK(&acdev->dwork, delayed_finish); dma_cap_set(DMA_MEMCPY, acdev->mask); - acdev->dma_priv = pdata->dma_priv; /* Handle platform specific quirks */ - if (pdata->quirk) { - if (pdata->quirk & CF_BROKEN_PIO) { + if (quirk) { + if (quirk & CF_BROKEN_PIO) { ap->ops->set_piomode = NULL; ap->pio_mask = 0; } - if (pdata->quirk & CF_BROKEN_MWDMA) + if (quirk & CF_BROKEN_MWDMA) ap->mwdma_mask = 0; - if (pdata->quirk & CF_BROKEN_UDMA) + if (quirk & CF_BROKEN_UDMA) ap->udma_mask = 0; } ap->flags |= ATA_FLAG_PIO_POLLING | ATA_FLAG_NO_ATAPI; diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 7bc6e51757e..c20de4a85cb 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -65,6 +65,7 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK config ARM_ARCH_TIMER bool + select CLKSRC_OF if OF config CLKSRC_METAG_GENERIC def_bool y if METAG diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index d7ad425ab9b..a2b25418978 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -248,14 +248,16 @@ static void __cpuinit arch_timer_stop(struct clock_event_device *clk) static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { - struct clock_event_device *evt = this_cpu_ptr(arch_timer_evt); - + /* + * Grab cpu pointer in each case to avoid spurious + * preemptible warnings + */ switch (action & ~CPU_TASKS_FROZEN) { case CPU_STARTING: - arch_timer_setup(evt); + arch_timer_setup(this_cpu_ptr(arch_timer_evt)); break; case CPU_DYING: - arch_timer_stop(evt); + arch_timer_stop(this_cpu_ptr(arch_timer_evt)); break; } @@ -337,22 +339,14 @@ out: return err; } -static const struct of_device_id arch_timer_of_match[] __initconst = { - { .compatible = "arm,armv7-timer", }, - { .compatible = "arm,armv8-timer", }, - {}, -}; - -int __init arch_timer_init(void) +static void __init arch_timer_init(struct device_node *np) { - struct device_node *np; u32 freq; int i; - np = of_find_matching_node(NULL, arch_timer_of_match); - if (!np) { - pr_err("arch_timer: can't find DT node\n"); - return -ENODEV; + if (arch_timer_get_rate()) { + pr_warn("arch_timer: multiple nodes in dt, skipping\n"); + return; } /* Try to determine the frequency from the device tree or CNTFRQ */ @@ -378,7 +372,7 @@ int __init arch_timer_init(void) if (!arch_timer_ppi[PHYS_SECURE_PPI] || !arch_timer_ppi[PHYS_NONSECURE_PPI]) { pr_warn("arch_timer: No interrupt available, giving up\n"); - return -EINVAL; + return; } } @@ -387,5 +381,8 @@ int __init arch_timer_init(void) else arch_timer_read_counter = arch_counter_get_cntpct; - return arch_timer_register(); + arch_timer_register(); + arch_timer_arch_init(); } +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); +CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 661026834b2..13a9e4923a0 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -24,7 +24,6 @@ #include <linux/of_address.h> #include <linux/clocksource.h> -#include <asm/arch_timer.h> #include <asm/localtimer.h> #include <plat/cpu.h> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c28fcccf4a0..cda4cb5f732 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o +obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o obj-$(CONFIG_ARCH_MXS) += irq-mxs.o obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o obj-$(CONFIG_METAG) += irq-metag-ext.o diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c new file mode 100644 index 00000000000..bb328a36612 --- /dev/null +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -0,0 +1,288 @@ +/* + * Marvell Armada 370 and Armada XP SoC IRQ handling + * + * Copyright (C) 2012 Marvell + * + * Lior Amsalem <alior@marvell.com> + * Gregory CLEMENT <gregory.clement@free-electrons.com> + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + * Ben Dooks <ben.dooks@codethink.co.uk> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/irqdomain.h> +#include <asm/mach/arch.h> +#include <asm/exception.h> +#include <asm/smp_plat.h> +#include <asm/mach/irq.h> + +#include "irqchip.h" + +/* Interrupt Controller Registers Map */ +#define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) +#define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) + +#define ARMADA_370_XP_INT_CONTROL (0x00) +#define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) +#define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34) +#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4) + +#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) + +#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4) +#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc) +#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8) + +#define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) + +#define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5) + +#define IPI_DOORBELL_START (0) +#define IPI_DOORBELL_END (8) +#define IPI_DOORBELL_MASK 0xFF + +static DEFINE_RAW_SPINLOCK(irq_controller_lock); + +static void __iomem *per_cpu_int_base; +static void __iomem *main_int_base; +static struct irq_domain *armada_370_xp_mpic_domain; + +/* + * In SMP mode: + * For shared global interrupts, mask/unmask global enable bit + * For CPU interrupts, mask/unmask the calling CPU's bit + */ +static void armada_370_xp_irq_mask(struct irq_data *d) +{ + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) + writel(hwirq, main_int_base + + ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); + else + writel(hwirq, per_cpu_int_base + + ARMADA_370_XP_INT_SET_MASK_OFFS); +} + +static void armada_370_xp_irq_unmask(struct irq_data *d) +{ + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) + writel(hwirq, main_int_base + + ARMADA_370_XP_INT_SET_ENABLE_OFFS); + else + writel(hwirq, per_cpu_int_base + + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); +} + +#ifdef CONFIG_SMP +static int armada_xp_set_affinity(struct irq_data *d, + const struct cpumask *mask_val, bool force) +{ + unsigned long reg; + unsigned long new_mask = 0; + unsigned long online_mask = 0; + unsigned long count = 0; + irq_hw_number_t hwirq = irqd_to_hwirq(d); + int cpu; + + for_each_cpu(cpu, mask_val) { + new_mask |= 1 << cpu_logical_map(cpu); + count++; + } + + /* + * Forbid mutlicore interrupt affinity + * This is required since the MPIC HW doesn't limit + * several CPUs from acknowledging the same interrupt. + */ + if (count > 1) + return -EINVAL; + + for_each_cpu(cpu, cpu_online_mask) + online_mask |= 1 << cpu_logical_map(cpu); + + raw_spin_lock(&irq_controller_lock); + + reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); + reg = (reg & (~online_mask)) | new_mask; + writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); + + raw_spin_unlock(&irq_controller_lock); + + return 0; +} +#endif + +static struct irq_chip armada_370_xp_irq_chip = { + .name = "armada_370_xp_irq", + .irq_mask = armada_370_xp_irq_mask, + .irq_mask_ack = armada_370_xp_irq_mask, + .irq_unmask = armada_370_xp_irq_unmask, +#ifdef CONFIG_SMP + .irq_set_affinity = armada_xp_set_affinity, +#endif +}; + +static int armada_370_xp_mpic_irq_map(struct irq_domain *h, + unsigned int virq, irq_hw_number_t hw) +{ + armada_370_xp_irq_mask(irq_get_irq_data(virq)); + if (hw != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) + writel(hw, per_cpu_int_base + + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + else + writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); + irq_set_status_flags(virq, IRQ_LEVEL); + + if (hw == ARMADA_370_XP_TIMER0_PER_CPU_IRQ) { + irq_set_percpu_devid(virq); + irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, + handle_percpu_devid_irq); + + } else { + irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, + handle_level_irq); + } + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + + return 0; +} + +#ifdef CONFIG_SMP +void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq) +{ + int cpu; + unsigned long map = 0; + + /* Convert our logical CPU mask into a physical one. */ + for_each_cpu(cpu, mask) + map |= 1 << cpu_logical_map(cpu); + + /* + * Ensure that stores to Normal memory are visible to the + * other CPUs before issuing the IPI. + */ + dsb(); + + /* submit softirq */ + writel((map << 8) | irq, main_int_base + + ARMADA_370_XP_SW_TRIG_INT_OFFS); +} + +void armada_xp_mpic_smp_cpu_init(void) +{ + /* Clear pending IPIs */ + writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); + + /* Enable first 8 IPIs */ + writel(IPI_DOORBELL_MASK, per_cpu_int_base + + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); + + /* Unmask IPI interrupt */ + writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); +} +#endif /* CONFIG_SMP */ + +static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { + .map = armada_370_xp_mpic_irq_map, + .xlate = irq_domain_xlate_onecell, +}; + +static asmlinkage void __exception_irq_entry +armada_370_xp_handle_irq(struct pt_regs *regs) +{ + u32 irqstat, irqnr; + + do { + irqstat = readl_relaxed(per_cpu_int_base + + ARMADA_370_XP_CPU_INTACK_OFFS); + irqnr = irqstat & 0x3FF; + + if (irqnr > 1022) + break; + + if (irqnr > 0) { + irqnr = irq_find_mapping(armada_370_xp_mpic_domain, + irqnr); + handle_IRQ(irqnr, regs); + continue; + } +#ifdef CONFIG_SMP + /* IPI Handling */ + if (irqnr == 0) { + u32 ipimask, ipinr; + + ipimask = readl_relaxed(per_cpu_int_base + + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) + & IPI_DOORBELL_MASK; + + writel(~IPI_DOORBELL_MASK, per_cpu_int_base + + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); + + /* Handle all pending doorbells */ + for (ipinr = IPI_DOORBELL_START; + ipinr < IPI_DOORBELL_END; ipinr++) { + if (ipimask & (0x1 << ipinr)) + handle_IPI(ipinr, regs); + } + continue; + } +#endif + + } while (1); +} + +static int __init armada_370_xp_mpic_of_init(struct device_node *node, + struct device_node *parent) +{ + u32 control; + + main_int_base = of_iomap(node, 0); + per_cpu_int_base = of_iomap(node, 1); + + BUG_ON(!main_int_base); + BUG_ON(!per_cpu_int_base); + + control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); + + armada_370_xp_mpic_domain = + irq_domain_add_linear(node, (control >> 2) & 0x3ff, + &armada_370_xp_mpic_irq_ops, NULL); + + if (!armada_370_xp_mpic_domain) + panic("Unable to add Armada_370_Xp MPIC irq domain (DT)\n"); + + irq_set_default_host(armada_370_xp_mpic_domain); + +#ifdef CONFIG_SMP + armada_xp_mpic_smp_cpu_init(); + + /* + * Set the default affinity from all CPUs to the boot cpu. + * This is required since the MPIC doesn't limit several CPUs + * from acknowledging the same interrupt. + */ + cpumask_clear(irq_default_affinity); + cpumask_set_cpu(smp_processor_id(), irq_default_affinity); + +#endif + + set_handle_irq(armada_370_xp_handle_irq); + + return 0; +} + +IRQCHIP_DECLARE(armada_370_xp_mpic, "marvell,mpic", armada_370_xp_mpic_of_init); diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index b0fe393c882..371cc66f1a0 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1139,6 +1139,35 @@ err_no_rxchan: return -ENODEV; } +static int pl022_dma_autoprobe(struct pl022 *pl022) +{ + struct device *dev = &pl022->adev->dev; + + /* automatically configure DMA channels from platform, normally using DT */ + pl022->dma_rx_channel = dma_request_slave_channel(dev, "rx"); + if (!pl022->dma_rx_channel) + goto err_no_rxchan; + + pl022->dma_tx_channel = dma_request_slave_channel(dev, "tx"); + if (!pl022->dma_tx_channel) + goto err_no_txchan; + + pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!pl022->dummypage) + goto err_no_dummypage; + + return 0; + +err_no_dummypage: + dma_release_channel(pl022->dma_tx_channel); + pl022->dma_tx_channel = NULL; +err_no_txchan: + dma_release_channel(pl022->dma_rx_channel); + pl022->dma_rx_channel = NULL; +err_no_rxchan: + return -ENODEV; +} + static void terminate_dma(struct pl022 *pl022) { struct dma_chan *rxchan = pl022->dma_rx_channel; @@ -1167,6 +1196,11 @@ static inline int configure_dma(struct pl022 *pl022) return -ENODEV; } +static inline int pl022_dma_autoprobe(struct pl022 *pl022) +{ + return 0; +} + static inline int pl022_dma_probe(struct pl022 *pl022) { return 0; @@ -2226,8 +2260,13 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_irq; } - /* Get DMA channels */ - if (platform_info->enable_dma) { + /* Get DMA channels, try autoconfiguration first */ + status = pl022_dma_autoprobe(pl022); + + /* If that failed, use channels from platform_info */ + if (status == 0) + platform_info->enable_dma = 1; + else if (platform_info->enable_dma) { status = pl022_dma_probe(pl022); if (status != 0) platform_info->enable_dma = 0; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index b2e9e177a35..8ab70a62091 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -267,7 +267,7 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg, } } -static void pl011_dma_probe_initcall(struct uart_amba_port *uap) +static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap) { /* DMA is the sole user of the platform data right now */ struct amba_pl011_data *plat = uap->port.dev->platform_data; @@ -281,20 +281,25 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) struct dma_chan *chan; dma_cap_mask_t mask; - /* We need platform data */ - if (!plat || !plat->dma_filter) { - dev_info(uap->port.dev, "no DMA platform data\n"); - return; - } + chan = dma_request_slave_channel(dev, "tx"); - /* Try to acquire a generic DMA engine slave TX channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param); if (!chan) { - dev_err(uap->port.dev, "no TX DMA channel!\n"); - return; + /* We need platform data */ + if (!plat || !plat->dma_filter) { + dev_info(uap->port.dev, "no DMA platform data\n"); + return; + } + + /* Try to acquire a generic DMA engine slave TX channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + chan = dma_request_channel(mask, plat->dma_filter, + plat->dma_tx_param); + if (!chan) { + dev_err(uap->port.dev, "no TX DMA channel!\n"); + return; + } } dmaengine_slave_config(chan, &tx_conf); @@ -304,7 +309,18 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) dma_chan_name(uap->dmatx.chan)); /* Optionally make use of an RX channel as well */ - if (plat->dma_rx_param) { + chan = dma_request_slave_channel(dev, "rx"); + + if (!chan && plat->dma_rx_param) { + chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); + + if (!chan) { + dev_err(uap->port.dev, "no RX DMA channel!\n"); + return; + } + } + + if (chan) { struct dma_slave_config rx_conf = { .src_addr = uap->port.mapbase + UART01x_DR, .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, @@ -313,12 +329,6 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) .device_fc = false, }; - chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); - if (!chan) { - dev_err(uap->port.dev, "no RX DMA channel!\n"); - return; - } - dmaengine_slave_config(chan, &rx_conf); uap->dmarx.chan = chan; @@ -360,6 +370,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) struct dma_uap { struct list_head node; struct uart_amba_port *uap; + struct device *dev; }; static LIST_HEAD(pl011_dma_uarts); @@ -370,7 +381,7 @@ static int __init pl011_dma_initcall(void) list_for_each_safe(node, tmp, &pl011_dma_uarts) { struct dma_uap *dmau = list_entry(node, struct dma_uap, node); - pl011_dma_probe_initcall(dmau->uap); + pl011_dma_probe_initcall(dmau->dev, dmau->uap); list_del(node); kfree(dmau); } @@ -379,18 +390,19 @@ static int __init pl011_dma_initcall(void) device_initcall(pl011_dma_initcall); -static void pl011_dma_probe(struct uart_amba_port *uap) +static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) { struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); if (dmau) { dmau->uap = uap; + dmau->dev = dev; list_add_tail(&dmau->node, &pl011_dma_uarts); } } #else -static void pl011_dma_probe(struct uart_amba_port *uap) +static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) { - pl011_dma_probe_initcall(uap); + pl011_dma_probe_initcall(dev, uap); } #endif @@ -1096,7 +1108,7 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #else /* Blank functions if the DMA engine is not available */ -static inline void pl011_dma_probe(struct uart_amba_port *uap) +static inline void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) { } @@ -2155,7 +2167,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = i; - pl011_dma_probe(uap); + pl011_dma_probe(&dev->dev, uap); /* Ensure interrupts from this UART are masked and cleared */ writew(0, uap->port.membase + UART011_IMSC); |