diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2011-03-03 11:48:25 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2011-03-03 11:48:25 +1100 |
commit | 30f3eb26bff0728246b25db68bc812e1b1b09995 (patch) | |
tree | 35eec5b17ba8be00cd5b7163c956d9e784324b2d /drivers | |
parent | 393a10734153fdb74bfc97dbf12fc03a5d2cd99a (diff) | |
parent | 0b5a2ef525da60533bada974b51d261037a9ca42 (diff) |
Merge remote-tracking branch 'arm/for-next'
Diffstat (limited to 'drivers')
31 files changed, 998 insertions, 3669 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index e7df019d29d4..6d2bb2524b6e 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -13,16 +13,17 @@ #include <linux/string.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/amba/bus.h> #include <asm/irq.h> #include <asm/sizes.h> -#define to_amba_device(d) container_of(d, struct amba_device, dev) #define to_amba_driver(d) container_of(d, struct amba_driver, drv) -static struct amba_id * -amba_lookup(struct amba_id *table, struct amba_device *dev) +static const struct amba_id * +amba_lookup(const struct amba_id *table, struct amba_device *dev) { int ret = 0; @@ -57,26 +58,6 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) #define amba_uevent NULL #endif -static int amba_suspend(struct device *dev, pm_message_t state) -{ - struct amba_driver *drv = to_amba_driver(dev->driver); - int ret = 0; - - if (dev->driver && drv->suspend) - ret = drv->suspend(to_amba_device(dev), state); - return ret; -} - -static int amba_resume(struct device *dev) -{ - struct amba_driver *drv = to_amba_driver(dev->driver); - int ret = 0; - - if (dev->driver && drv->resume) - ret = drv->resume(to_amba_device(dev)); - return ret; -} - #define amba_attr_func(name,fmt,arg...) \ static ssize_t name##_show(struct device *_dev, \ struct device_attribute *attr, char *buf) \ @@ -102,17 +83,330 @@ static struct device_attribute amba_dev_attrs[] = { __ATTR_NULL, }; +#ifdef CONFIG_PM_SLEEP + +static int amba_legacy_suspend(struct device *dev, pm_message_t mesg) +{ + struct amba_driver *adrv = to_amba_driver(dev->driver); + struct amba_device *adev = to_amba_device(dev); + int ret = 0; + + if (dev->driver && adrv->suspend) + ret = adrv->suspend(adev, mesg); + + return ret; +} + +static int amba_legacy_resume(struct device *dev) +{ + struct amba_driver *adrv = to_amba_driver(dev->driver); + struct amba_device *adev = to_amba_device(dev); + int ret = 0; + + if (dev->driver && adrv->resume) + ret = adrv->resume(adev); + + return ret; +} + +static int amba_pm_prepare(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (drv && drv->pm && drv->pm->prepare) + ret = drv->pm->prepare(dev); + + return ret; +} + +static void amba_pm_complete(struct device *dev) +{ + struct device_driver *drv = dev->driver; + + if (drv && drv->pm && drv->pm->complete) + drv->pm->complete(dev); +} + +#else /* !CONFIG_PM_SLEEP */ + +#define amba_pm_prepare NULL +#define amba_pm_complete NULL + +#endif /* !CONFIG_PM_SLEEP */ + +#ifdef CONFIG_SUSPEND + +static int amba_pm_suspend(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->suspend) + ret = drv->pm->suspend(dev); + } else { + ret = amba_legacy_suspend(dev, PMSG_SUSPEND); + } + + return ret; +} + +static int amba_pm_suspend_noirq(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->suspend_noirq) + ret = drv->pm->suspend_noirq(dev); + } + + return ret; +} + +static int amba_pm_resume(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->resume) + ret = drv->pm->resume(dev); + } else { + ret = amba_legacy_resume(dev); + } + + return ret; +} + +static int amba_pm_resume_noirq(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->resume_noirq) + ret = drv->pm->resume_noirq(dev); + } + + return ret; +} + +#else /* !CONFIG_SUSPEND */ + +#define amba_pm_suspend NULL +#define amba_pm_resume NULL +#define amba_pm_suspend_noirq NULL +#define amba_pm_resume_noirq NULL + +#endif /* !CONFIG_SUSPEND */ + +#ifdef CONFIG_HIBERNATION + +static int amba_pm_freeze(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->freeze) + ret = drv->pm->freeze(dev); + } else { + ret = amba_legacy_suspend(dev, PMSG_FREEZE); + } + + return ret; +} + +static int amba_pm_freeze_noirq(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->freeze_noirq) + ret = drv->pm->freeze_noirq(dev); + } + + return ret; +} + +static int amba_pm_thaw(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->thaw) + ret = drv->pm->thaw(dev); + } else { + ret = amba_legacy_resume(dev); + } + + return ret; +} + +static int amba_pm_thaw_noirq(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->thaw_noirq) + ret = drv->pm->thaw_noirq(dev); + } + + return ret; +} + +static int amba_pm_poweroff(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->poweroff) + ret = drv->pm->poweroff(dev); + } else { + ret = amba_legacy_suspend(dev, PMSG_HIBERNATE); + } + + return ret; +} + +static int amba_pm_poweroff_noirq(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->poweroff_noirq) + ret = drv->pm->poweroff_noirq(dev); + } + + return ret; +} + +static int amba_pm_restore(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->restore) + ret = drv->pm->restore(dev); + } else { + ret = amba_legacy_resume(dev); + } + + return ret; +} + +static int amba_pm_restore_noirq(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->restore_noirq) + ret = drv->pm->restore_noirq(dev); + } + + return ret; +} + +#else /* !CONFIG_HIBERNATION */ + +#define amba_pm_freeze NULL +#define amba_pm_thaw NULL +#define amba_pm_poweroff NULL +#define amba_pm_restore NULL +#define amba_pm_freeze_noirq NULL +#define amba_pm_thaw_noirq NULL +#define amba_pm_poweroff_noirq NULL +#define amba_pm_restore_noirq NULL + +#endif /* !CONFIG_HIBERNATION */ + +#ifdef CONFIG_PM + +static const struct dev_pm_ops amba_pm = { + .prepare = amba_pm_prepare, + .complete = amba_pm_complete, + .suspend = amba_pm_suspend, + .resume = amba_pm_resume, + .freeze = amba_pm_freeze, + .thaw = amba_pm_thaw, + .poweroff = amba_pm_poweroff, + .restore = amba_pm_restore, + .suspend_noirq = amba_pm_suspend_noirq, + .resume_noirq = amba_pm_resume_noirq, + .freeze_noirq = amba_pm_freeze_noirq, + .thaw_noirq = amba_pm_thaw_noirq, + .poweroff_noirq = amba_pm_poweroff_noirq, + .restore_noirq = amba_pm_restore_noirq, + SET_RUNTIME_PM_OPS( + pm_generic_runtime_suspend, + pm_generic_runtime_resume, + pm_generic_runtime_idle + ) +}; + +#define AMBA_PM (&amba_pm) + +#else /* !CONFIG_PM */ + +#define AMBA_PM NULL + +#endif /* !CONFIG_PM */ + /* * Primecells are part of the Advanced Microcontroller Bus Architecture, * so we call the bus "amba". */ -static struct bus_type amba_bustype = { +struct bus_type amba_bustype = { .name = "amba", .dev_attrs = amba_dev_attrs, .match = amba_match, .uevent = amba_uevent, - .suspend = amba_suspend, - .resume = amba_resume, + .pm = AMBA_PM, }; static int __init amba_init(void) @@ -188,7 +482,7 @@ static int amba_probe(struct device *dev) { struct amba_device *pcdev = to_amba_device(dev); struct amba_driver *pcdrv = to_amba_driver(dev->driver); - struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev); + const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev); int ret; do { diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c index a348c7e9aa0b..dd1d143eb8ea 100644 --- a/drivers/char/hw_random/nomadik-rng.c +++ b/drivers/char/hw_random/nomadik-rng.c @@ -39,7 +39,7 @@ static struct hwrng nmk_rng = { .read = nmk_rng_read, }; -static int nmk_rng_probe(struct amba_device *dev, struct amba_id *id) +static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) { void __iomem *base; int ret; diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 07bca4970e50..e6d7228b1479 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1845,7 +1845,7 @@ static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x) } #endif -static int pl08x_probe(struct amba_device *adev, struct amba_id *id) +static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) { struct pl08x_driver_data *pl08x; const struct vendor_data *vd = id->data; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 7c50f6dfd3f4..6abe1ec1f2ce 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -657,7 +657,7 @@ static irqreturn_t pl330_irq_handler(int irq, void *data) } static int __devinit -pl330_probe(struct amba_device *adev, struct amba_id *id) +pl330_probe(struct amba_device *adev, const struct amba_id *id) { struct dma_pl330_platdata *pdat; struct dma_pl330_dmac *pdmac; diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index 2975d22daffe..838ddbdf90cc 100644 --- a/drivers/gpio/pl061.c +++ b/drivers/gpio/pl061.c @@ -232,7 +232,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) desc->irq_data.chip->irq_unmask(&desc->irq_data); } -static int pl061_probe(struct amba_device *dev, struct amba_id *id) +static int pl061_probe(struct amba_device *dev, const struct amba_id *id) { struct pl061_platform_data *pdata; struct pl061_gpio *chip; diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 92563a681d65..12abc50508e5 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -107,7 +107,8 @@ static void amba_kmi_close(struct serio *io) clk_disable(kmi->clk); } -static int __devinit amba_kmi_probe(struct amba_device *dev, struct amba_id *id) +static int __devinit amba_kmi_probe(struct amba_device *dev, + const struct amba_id *id) { struct amba_kmi_port *kmi; struct serio *io; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2d6de3e03e2d..5bbb87d10251 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -2,7 +2,7 @@ * linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver * * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * Copyright (C) 2010 ST-Ericsson AB. + * Copyright (C) 2010 ST-Ericsson SA * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -25,8 +25,10 @@ #include <linux/clk.h> #include <linux/scatterlist.h> #include <linux/gpio.h> -#include <linux/amba/mmci.h> #include <linux/regulator/consumer.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/amba/mmci.h> #include <asm/div64.h> #include <asm/io.h> @@ -142,9 +144,6 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) host->mrq = NULL; host->cmd = NULL; - if (mrq->data) - mrq->data->bytes_xfered = host->data_xfered; - /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... @@ -189,6 +188,248 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); } +/* + * All the DMA operation mode stuff goes inside this ifdef. + * This assumes that you have a generic DMA device interface, + * no custom DMA interfaces are supported. + */ +#ifdef CONFIG_DMA_ENGINE +static void __devinit mmci_dma_setup(struct mmci_host *host) +{ + struct mmci_platform_data *plat = host->plat; + const char *rxname, *txname; + dma_cap_mask_t mask; + + if (!plat || !plat->dma_filter) { + dev_info(mmc_dev(host->mmc), "no DMA platform data\n"); + return; + } + + /* Try to acquire a generic DMA engine slave channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* + * If only an RX channel is specified, the driver will + * attempt to use it bidirectionally, however if it is + * is specified but cannot be located, DMA will be disabled. + */ + if (plat->dma_rx_param) { + host->dma_rx_channel = dma_request_channel(mask, + plat->dma_filter, + plat->dma_rx_param); + /* E.g if no DMA hardware is present */ + if (!host->dma_rx_channel) + dev_err(mmc_dev(host->mmc), "no RX DMA channel\n"); + } + + if (plat->dma_tx_param) { + host->dma_tx_channel = dma_request_channel(mask, + plat->dma_filter, + plat->dma_tx_param); + if (!host->dma_tx_channel) + dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n"); + } else { + host->dma_tx_channel = host->dma_rx_channel; + } + + if (host->dma_rx_channel) + rxname = dma_chan_name(host->dma_rx_channel); + else + rxname = "none"; + + if (host->dma_tx_channel) + txname = dma_chan_name(host->dma_tx_channel); + else + txname = "none"; + + dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n", + rxname, txname); + + /* + * Limit the maximum segment size in any SG entry according to + * the parameters of the DMA engine device. + */ + if (host->dma_tx_channel) { + struct device *dev = host->dma_tx_channel->device->dev; + unsigned int max_seg_size = dma_get_max_seg_size(dev); + + if (max_seg_size < host->mmc->max_seg_size) + host->mmc->max_seg_size = max_seg_size; + } + if (host->dma_rx_channel) { + struct device *dev = host->dma_rx_channel->device->dev; + unsigned int max_seg_size = dma_get_max_seg_size(dev); + + if (max_seg_size < host->mmc->max_seg_size) + host->mmc->max_seg_size = max_seg_size; + } +} + +/* + * This is used in __devinit or __devexit so inline it + * so it can be discarded. + */ +static inline void mmci_dma_release(struct mmci_host *host) +{ + struct mmci_platform_data *plat = host->plat; + + if (host->dma_rx_channel) + dma_release_channel(host->dma_rx_channel); + if (host->dma_tx_channel && plat->dma_tx_param) + dma_release_channel(host->dma_tx_channel); + host->dma_rx_channel = host->dma_tx_channel = NULL; +} + +static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) +{ + struct dma_chan *chan = host->dma_current; + enum dma_data_direction dir; + u32 status; + int i; + + /* Wait up to 1ms for the DMA to complete */ + for (i = 0; ; i++) { + status = readl(host->base + MMCISTATUS); + if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100) + break; + udelay(10); + } + + /* + * Check to see whether we still have some data left in the FIFO - + * this catches DMA controllers which are unable to monitor the + * DMALBREQ and DMALSREQ signals while allowing us to DMA to non- + * contiguous buffers. On TX, we'll get a FIFO underrun error. + */ + if (status & MCI_RXDATAAVLBLMASK) { + dmaengine_terminate_all(chan); + if (!data->error) + data->error = -EIO; + } + + if (data->flags & MMC_DATA_WRITE) { + dir = DMA_TO_DEVICE; + } else { + dir = DMA_FROM_DEVICE; + } + + dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); + + /* + * Use of DMA with scatter-gather is impossible. + * Give up with DMA and switch back to PIO mode. + */ + if (status & MCI_RXDATAAVLBLMASK) { + dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n"); + mmci_dma_release(host); + } +} + +static void mmci_dma_data_error(struct mmci_host *host) +{ + dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); + dmaengine_terminate_all(host->dma_current); +} + +static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +{ + struct variant_data *variant = host->variant; + struct dma_slave_config conf = { + .src_addr = host->phybase + MMCIFIFO, + .dst_addr = host->phybase + MMCIFIFO, + .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .src_maxburst = variant->fifohalfsize >> 2, /* # of words */ + .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */ + }; + struct mmc_data *data = host->data; + struct dma_chan *chan; + struct dma_device *device; + struct dma_async_tx_descriptor *desc; + int nr_sg; + + host->dma_current = NULL; + + if (data->flags & MMC_DATA_READ) { + conf.direction = DMA_FROM_DEVICE; + chan = host->dma_rx_channel; + } else { + conf.direction = DMA_TO_DEVICE; + chan = host->dma_tx_channel; + } + + /* If there's no DMA channel, fall back to PIO */ + if (!chan) + return -EINVAL; + + /* If less than or equal to the fifo size, don't bother with DMA */ + if (host->size <= variant->fifosize) + return -EINVAL; + + device = chan->device; + nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, conf.direction); + if (nr_sg == 0) + return -EINVAL; + + dmaengine_slave_config(chan, &conf); + desc = device->device_prep_slave_sg(chan, data->sg, nr_sg, + conf.direction, DMA_CTRL_ACK); + if (!desc) + goto unmap_exit; + + /* Okay, go for it. */ + host->dma_current = chan; + + dev_vdbg(mmc_dev(host->mmc), + "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", + data->sg_len, data->blksz, data->blocks, data->flags); + dmaengine_submit(desc); + dma_async_issue_pending(chan); + + datactrl |= MCI_DPSM_DMAENABLE; + + /* Trigger the DMA transfer */ + writel(datactrl, host->base + MMCIDATACTRL); + + /* + * Let the MMCI say when the data is ended and it's time + * to fire next DMA request. When that happens, MMCI will + * call mmci_data_end() + */ + writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, + host->base + MMCIMASK0); + return 0; + +unmap_exit: + dmaengine_terminate_all(chan); + dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction); + return -ENOMEM; +} +#else +/* Blank functions if the DMA engine is not available */ +static inline void mmci_dma_setup(struct mmci_host *host) +{ +} + +static inline void mmci_dma_release(struct mmci_host *host) +{ +} + +static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) +{ +} + +static inline void mmci_dma_data_error(struct mmci_host *host) +{ +} + +static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +{ + return -ENOSYS; +} +#endif + static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { struct variant_data *variant = host->variant; @@ -202,9 +443,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) host->data = data; host->size = data->blksz * data->blocks; - host->data_xfered = 0; - - mmci_init_sg(host, data); + data->bytes_xfered = 0; clks = (unsigned long long)data->timeout_ns * host->cclk; do_div(clks, 1000000000UL); @@ -219,15 +458,29 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) BUG_ON(1 << blksz_bits != data->blksz); datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; - if (data->flags & MMC_DATA_READ) { + + if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; + + /* + * Attempt to use DMA operation mode, if this + * should fail, fall back to PIO mode + */ + if (!mmci_dma_start_data(host, datactrl)) + return; + + /* IRQ mode, map the SG list for CPU reading/writing */ + mmci_init_sg(host, data); + + if (data->flags & MMC_DATA_READ) { irqmask = MCI_RXFIFOHALFFULLMASK; /* - * If we have less than a FIFOSIZE of bytes to transfer, - * trigger a PIO interrupt as soon as any data is available. + * If we have less than the fifo 'half-full' threshold to + * transfer, trigger a PIO interrupt as soon as any data + * is available. */ - if (host->size < variant->fifosize) + if (host->size < variant->fifohalfsize) irqmask |= MCI_RXDATAAVLBLMASK; } else { /* @@ -283,49 +536,51 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { u32 remain, success; - /* Calculate how far we are into the transfer */ + /* Terminate the DMA transfer */ + if (dma_inprogress(host)) + mmci_dma_data_error(host); + + /* + * Calculate how far we are into the transfer. Note that + * the data counter gives the number of bytes transferred + * on the MMC bus, not on the host side. On reads, this + * can be as much as a FIFO-worth of data ahead. This + * matters for FIFO overruns only. + */ remain = readl(host->base + MMCIDATACNT); success = data->blksz * data->blocks - remain; - dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); + dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n", + status, success); if (status & MCI_DATACRCFAIL) { /* Last block was not successful */ - host->data_xfered = round_down(success - 1, data->blksz); + success -= 1; data->error = -EILSEQ; } else if (status & MCI_DATATIMEOUT) { - host->data_xfered = round_down(success, data->blksz); data->error = -ETIMEDOUT; - } else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) { - host->data_xfered = round_down(success, data->blksz); + } else if (status & MCI_TXUNDERRUN) { + data->error = -EIO; + } else if (status & MCI_RXOVERRUN) { + if (success > host->variant->fifosize) + success -= host->variant->fifosize; + else + success = 0; data->error = -EIO; } - - /* - * We hit an error condition. Ensure that any data - * partially written to a page is properly coherent. - */ - if (data->flags & MMC_DATA_READ) { - struct sg_mapping_iter *sg_miter = &host->sg_miter; - unsigned long flags; - - local_irq_save(flags); - if (sg_miter_next(sg_miter)) { - flush_dcache_page(sg_miter->page); - sg_miter_stop(sg_miter); - } - local_irq_restore(flags); - } + data->bytes_xfered = round_down(success, data->blksz); } if (status & MCI_DATABLOCKEND) dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); if (status & MCI_DATAEND || data->error) { + if (dma_inprogress(host)) + mmci_dma_unmap(host, data); mmci_stop_data(host); if (!data->error) /* The error clause is handled above, success! */ - host->data_xfered += data->blksz * data->blocks; + data->bytes_xfered = data->blksz * data->blocks; if (!data->stop) { mmci_request_end(host, data->mrq); @@ -498,9 +753,6 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) if (remain) break; - if (status & MCI_RXACTIVE) - flush_dcache_page(sg_miter->page); - status = readl(base + MMCISTATUS); } while (1); @@ -509,10 +761,10 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) local_irq_restore(flags); /* - * If we're nearing the end of the read, switch to - * "any data available" mode. + * If we have less than the fifo 'half-full' threshold to transfer, + * trigger a PIO interrupt as soon as any data is available. */ - if (status & MCI_RXACTIVE && host->size < variant->fifosize) + if (status & MCI_RXACTIVE && host->size < variant->fifohalfsize) mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); /* @@ -713,7 +965,8 @@ static const struct mmc_host_ops mmci_ops = { .get_cd = mmci_get_cd, }; -static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) +static int __devinit mmci_probe(struct amba_device *dev, + const struct amba_id *id) { struct mmci_platform_data *plat = dev->dev.platform_data; struct variant_data *variant = id->data; @@ -776,6 +1029,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n", host->mclk); } + host->phybase = dev->res.start; host->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!host->base) { ret = -ENOMEM; @@ -903,9 +1157,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) amba_set_drvdata(dev, mmc); - dev_info(&dev->dev, "%s: PL%03x rev%u at 0x%08llx irq %d,%d\n", - mmc_hostname(mmc), amba_part(dev), amba_rev(dev), - (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); + dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n", + mmc_hostname(mmc), amba_part(dev), amba_manf(dev), + amba_rev(dev), (unsigned long long)dev->res.start, + dev->irq[0], dev->irq[1]); + + mmci_dma_setup(host); mmc_add_host(mmc); @@ -952,6 +1209,7 @@ static int __devexit mmci_remove(struct amba_device *dev) writel(0, host->base + MMCICOMMAND); writel(0, host->base + MMCIDATACTRL); + mmci_dma_release(host); free_irq(dev->irq[0], host); if (!host->singleirq) free_irq(dev->irq[1], host); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index c1df7b82d36c..ec9a7bc6d0df 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -148,8 +148,10 @@ struct clk; struct variant_data; +struct dma_chan; struct mmci_host { + phys_addr_t phybase; void __iomem *base; struct mmc_request *mrq; struct mmc_command *cmd; @@ -161,8 +163,6 @@ struct mmci_host { int gpio_cd_irq; bool singleirq; - unsigned int data_xfered; - spinlock_t lock; unsigned int mclk; @@ -181,5 +181,16 @@ struct mmci_host { struct sg_mapping_iter sg_miter; unsigned int size; struct regulator *vcc; + +#ifdef CONFIG_DMA_ENGINE + /* DMA stuff */ + struct dma_chan *dma_current; + struct dma_chan *dma_rx_channel; + struct dma_chan *dma_tx_channel; + +#define dma_inprogress(host) ((host)->dma_current) +#else +#define dma_inprogress(host) (0) +#endif }; diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index ee747919a766..68d48ab6eacf 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -206,68 +206,6 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define RPC_LSA_DEFAULT RPC_LED_TX_RX #define RPC_LSB_DEFAULT RPC_LED_100_10 -#elif defined(CONFIG_MACH_LPD79520) || \ - defined(CONFIG_MACH_LPD7A400) || \ - defined(CONFIG_MACH_LPD7A404) - -/* The LPD7X_IOBARRIER is necessary to overcome a mismatch between the - * way that the CPU handles chip selects and the way that the SMC chip - * expects the chip select to operate. Refer to - * Documentation/arm/Sharp-LH/IOBarrier for details. The read from - * IOBARRIER is a byte, in order that we read the least-common - * denominator. It would be wasteful to read 32 bits from an 8-bit - * accessible region. - * - * There is no explicit protection against interrupts intervening - * between the writew and the IOBARRIER. In SMC ISR there is a - * preamble that performs an IOBARRIER in the extremely unlikely event - * that the driver interrupts itself between a writew to the chip an - * the IOBARRIER that follows *and* the cache is large enough that the - * first off-chip access while handing the interrupt is to the SMC - * chip. Other devices in the same address space as the SMC chip must - * be aware of the potential for trouble and perform a similar - * IOBARRIER on entry to their ISR. - */ - -#include <mach/constants.h> /* IOBARRIER_VIRT */ - -#define SMC_CAN_USE_8BIT 0 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 -#define SMC_NOWAIT 0 -#define LPD7X_IOBARRIER readb (IOBARRIER_VIRT) - -#define SMC_inw(a,r)\ - ({ unsigned short v = readw ((void*) ((a) + (r))); LPD7X_IOBARRIER; v; }) -#define SMC_outw(v,a,r) ({ writew ((v), (a) + (r)); LPD7X_IOBARRIER; }) - -#define SMC_insw LPD7_SMC_insw -static inline void LPD7_SMC_insw (unsigned char* a, int r, - unsigned char* p, int l) -{ - unsigned short* ps = (unsigned short*) p; - while (l-- > 0) { - *ps++ = readw (a + r); - LPD7X_IOBARRIER; - } -} - -#define SMC_outsw LPD7_SMC_outsw -static inline void LPD7_SMC_outsw (unsigned char* a, int r, - unsigned char* p, int l) -{ - unsigned short* ps = (unsigned short*) p; - while (l-- > 0) { - writew (*ps++, a + r); - LPD7X_IOBARRIER; - } -} - -#define SMC_INTERRUPT_PREAMBLE LPD7X_IOBARRIER - -#define RPC_LSA_DEFAULT RPC_LED_TX_RX -#define RPC_LSB_DEFAULT RPC_LED_100_10 - #elif defined(CONFIG_ARCH_VERSATILE) #define SMC_CAN_USE_8BIT 1 diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index bbdb2f02798a..baff724cd40f 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -103,7 +103,7 @@ static const struct rtc_class_ops pl030_ops = { .set_alarm = pl030_set_alarm, }; -static int pl030_probe(struct amba_device *dev, struct amba_id *id) +static int pl030_probe(struct amba_device *dev, const struct amba_id *id) { struct pl030_rtc *rtc; int ret; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index b7a6690e5b35..6568f4b37e19 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -358,7 +358,7 @@ static int pl031_remove(struct amba_device *adev) return 0; } -static int pl031_probe(struct amba_device *adev, struct amba_id *id) +static int pl031_probe(struct amba_device *adev, const struct amba_id *id) { int ret; struct pl031_local *ldata; diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index 71a1219a995d..95e58c70a2c9 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -2021,7 +2021,7 @@ static void pl022_cleanup(struct spi_device *spi) static int __devinit -pl022_probe(struct amba_device *adev, struct amba_id *id) +pl022_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; struct pl022_ssp_controller *platform_info = adev->dev.platform_data; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 2b8334601c8b..2bb248e8f13f 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1110,29 +1110,6 @@ config SERIAL_PMACZILOG_CONSOLE on your (Power)Mac as the console, you can do so by answering Y to this option. -config SERIAL_LH7A40X - tristate "Sharp LH7A40X embedded UART support" - depends on ARM && ARCH_LH7A40X - select SERIAL_CORE - help - This enables support for the three on-board UARTs of the - Sharp LH7A40X series CPUs. Choose Y or M. - -config SERIAL_LH7A40X_CONSOLE - bool "Support for console on Sharp LH7A40X serial port" - depends on SERIAL_LH7A40X=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use one of the serial ports as the - system console--the system console is the device which - receives all kernel messages and warnings and which allows - logins in single user mode. - - Even if you say Y here, the currently visible framebuffer console - (/dev/tty0) will still be used as the default system console, but - you can alter that using a kernel command line, for example - "console=ttyAM1". - config SERIAL_CPM tristate "CPM SCC/SMC serial port support" depends on CPM2 || 8xx diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 8ea92e9c73b0..8e325408b1a6 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -54,7 +54,6 @@ obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_68360) += 68360serial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o -obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_ZS) += zs.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 2904aa044126..d742dd2c525c 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -676,7 +676,7 @@ static struct uart_driver amba_reg = { .cons = AMBA_CONSOLE, }; -static int pl010_probe(struct amba_device *dev, struct amba_id *id) +static int pl010_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; void __iomem *base; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index e76d7d000128..0dae46f91021 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1349,7 +1349,7 @@ static struct uart_driver amba_reg = { .cons = AMBA_CONSOLE, }; -static int pl011_probe(struct amba_device *dev, struct amba_id *id) +static int pl011_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; struct vendor_data *vendor = id->data; diff --git a/drivers/tty/serial/serial_lh7a40x.c b/drivers/tty/serial/serial_lh7a40x.c deleted file mode 100644 index ea744707c4d6..000000000000 --- a/drivers/tty/serial/serial_lh7a40x.c +++ /dev/null @@ -1,682 +0,0 @@ -/* drivers/serial/serial_lh7a40x.c - * - * Copyright (C) 2004 Coastal Environmental Systems - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - */ - -/* Driver for Sharp LH7A40X embedded serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd. - * - * --- - * - * This driver supports the embedded UARTs of the Sharp LH7A40X series - * CPUs. While similar to the 16550 and other UART chips, there is - * nothing close to register compatibility. Moreover, some of the - * modem control lines are not available, either in the chip or they - * are lacking in the board-level implementation. - * - * - Use of SIRDIS - * For simplicity, we disable the IR functions of any UART whenever - * we enable it. - * - */ - - -#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include <linux/module.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/serial.h> -#include <linux/io.h> - -#include <asm/irq.h> -#include <mach/hardware.h> - -#define DEV_MAJOR 204 -#define DEV_MINOR 16 -#define DEV_NR 3 - -#define ISR_LOOP_LIMIT 256 - -#define UR(p,o) _UR ((p)->membase, o) -#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o)))) -#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m) -#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m) - -#define UART_REG_SIZE 32 - -#define UART_R_DATA (0x00) -#define UART_R_FCON (0x04) -#define UART_R_BRCON (0x08) -#define UART_R_CON (0x0c) -#define UART_R_STATUS (0x10) -#define UART_R_RAWISR (0x14) -#define UART_R_INTEN (0x18) -#define UART_R_ISR (0x1c) - -#define UARTEN (0x01) /* UART enable */ -#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */ - -#define RxEmpty (0x10) -#define TxEmpty (0x80) -#define TxFull (0x20) -#define nRxRdy RxEmpty -#define nTxRdy TxFull -#define TxBusy (0x08) - -#define RxBreak (0x0800) -#define RxOverrunError (0x0400) -#define RxParityError (0x0200) -#define RxFramingError (0x0100) -#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError) - -#define DCD (0x04) -#define DSR (0x02) -#define CTS (0x01) - -#define RxInt (0x01) -#define TxInt (0x02) -#define ModemInt (0x04) -#define RxTimeoutInt (0x08) - -#define MSEOI (0x10) - -#define WLEN_8 (0x60) -#define WLEN_7 (0x40) -#define WLEN_6 (0x20) -#define WLEN_5 (0x00) -#define WLEN (0x60) /* Mask for all word-length bits */ -#define STP2 (0x08) -#define PEN (0x02) /* Parity Enable */ -#define EPS (0x04) /* Even Parity Set */ -#define FEN (0x10) /* FIFO Enable */ -#define BRK (0x01) /* Send Break */ - - -struct uart_port_lh7a40x { - struct uart_port port; - unsigned int statusPrev; /* Most recently read modem status */ -}; - -static void lh7a40xuart_stop_tx (struct uart_port* port) -{ - BIT_CLR (port, UART_R_INTEN, TxInt); -} - -static void lh7a40xuart_start_tx (struct uart_port* port) -{ - BIT_SET (port, UART_R_INTEN, TxInt); - - /* *** FIXME: do I need to check for startup of the - transmitter? The old driver did, but AMBA - doesn't . */ -} - -static void lh7a40xuart_stop_rx (struct uart_port* port) -{ - BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); -} - -static void lh7a40xuart_enable_ms (struct uart_port* port) -{ - BIT_SET (port, UART_R_INTEN, ModemInt); -} - -static void lh7a40xuart_rx_chars (struct uart_port* port) -{ - struct tty_struct* tty = port->state->port.tty; - int cbRxMax = 256; /* (Gross) limit on receive */ - unsigned int data; /* Received data and status */ - unsigned int flag; - - while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) { - data = UR (port, UART_R_DATA); - flag = TTY_NORMAL; - ++port->icount.rx; - - if (unlikely(data & RxError)) { - if (data & RxBreak) { - data &= ~(RxFramingError | RxParityError); - ++port->icount.brk; - if (uart_handle_break (port)) - continue; - } - else if (data & RxParityError) - ++port->icount.parity; - else if (data & RxFramingError) - ++port->icount.frame; - if (data & RxOverrunError) - ++port->icount.overrun; - - /* Mask by termios, leave Rx'd byte */ - data &= port->read_status_mask | 0xff; - - if (data & RxBreak) - flag = TTY_BREAK; - else if (data & RxParityError) - flag = TTY_PARITY; - else if (data & RxFramingError) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char (port, (unsigned char) data)) - continue; - - uart_insert_char(port, data, RxOverrunError, data, flag); - } - tty_flip_buffer_push (tty); - return; -} - -static void lh7a40xuart_tx_chars (struct uart_port* port) -{ - struct circ_buf* xmit = &port->state->xmit; - int cbTxMax = port->fifosize; - - if (port->x_char) { - UR (port, UART_R_DATA) = port->x_char; - ++port->icount.tx; - port->x_char = 0; - return; - } - if (uart_circ_empty (xmit) || uart_tx_stopped (port)) { - lh7a40xuart_stop_tx (port); - return; - } - - /* Unlike the AMBA UART, the lh7a40x UART does not guarantee - that at least half of the FIFO is empty. Instead, we check - status for every character. Using the AMBA method causes - the transmitter to drop characters. */ - - do { - UR (port, UART_R_DATA) = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - ++port->icount.tx; - if (uart_circ_empty(xmit)) - break; - } while (!(UR (port, UART_R_STATUS) & nTxRdy) - && cbTxMax--); - - if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) - uart_write_wakeup (port); - - if (uart_circ_empty (xmit)) - lh7a40xuart_stop_tx (port); -} - -static void lh7a40xuart_modem_status (struct uart_port* port) -{ - unsigned int status = UR (port, UART_R_STATUS); - unsigned int delta - = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev; - - BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */ - - if (!delta) /* Only happens if we missed 2 transitions */ - return; - - ((struct uart_port_lh7a40x*) port)->statusPrev = status; - - if (delta & DCD) - uart_handle_dcd_change (port, status & DCD); - - if (delta & DSR) - ++port->icount.dsr; - - if (delta & CTS) - uart_handle_cts_change (port, status & CTS); - - wake_up_interruptible (&port->state->port.delta_msr_wait); -} - -static irqreturn_t lh7a40xuart_int (int irq, void* dev_id) -{ - struct uart_port* port = dev_id; - unsigned int cLoopLimit = ISR_LOOP_LIMIT; - unsigned int isr = UR (port, UART_R_ISR); - - - do { - if (isr & (RxInt | RxTimeoutInt)) - lh7a40xuart_rx_chars(port); - if (isr & ModemInt) - lh7a40xuart_modem_status (port); - if (isr & TxInt) - lh7a40xuart_tx_chars (port); - - if (--cLoopLimit == 0) - break; - - isr = UR (port, UART_R_ISR); - } while (isr & (RxInt | TxInt | RxTimeoutInt)); - - return IRQ_HANDLED; -} - -static unsigned int lh7a40xuart_tx_empty (struct uart_port* port) -{ - return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0; -} - -static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port) -{ - unsigned int result = 0; - unsigned int status = UR (port, UART_R_STATUS); - - if (status & DCD) - result |= TIOCM_CAR; - if (status & DSR) - result |= TIOCM_DSR; - if (status & CTS) - result |= TIOCM_CTS; - - return result; -} - -static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl) -{ - /* None of the ports supports DTR. UART1 supports RTS through GPIO. */ - /* Note, kernel appears to be setting DTR and RTS on console. */ - - /* *** FIXME: this deserves more work. There's some work in - tracing all of the IO pins. */ -#if 0 - if( port->mapbase == UART1_PHYS) { - gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); - - if (mctrl & TIOCM_RTS) - gpio->pbdr &= ~GPIOB_UART1_RTS; - else - gpio->pbdr |= GPIOB_UART1_RTS; - } -#endif -} - -static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state) -{ - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - if (break_state == -1) - BIT_SET (port, UART_R_FCON, BRK); /* Assert break */ - else - BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */ - spin_unlock_irqrestore(&port->lock, flags); -} - -static int lh7a40xuart_startup (struct uart_port* port) -{ - int retval; - - retval = request_irq (port->irq, lh7a40xuart_int, 0, - "serial_lh7a40x", port); - if (retval) - return retval; - - /* Initial modem control-line settings */ - ((struct uart_port_lh7a40x*) port)->statusPrev - = UR (port, UART_R_STATUS); - - /* There is presently no configuration option to enable IR. - Thus, we always disable it. */ - - BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); - BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); - - return 0; -} - -static void lh7a40xuart_shutdown (struct uart_port* port) -{ - free_irq (port->irq, port); - BIT_CLR (port, UART_R_FCON, BRK | FEN); - BIT_CLR (port, UART_R_CON, UARTEN); -} - -static void lh7a40xuart_set_termios (struct uart_port* port, - struct ktermios* termios, - struct ktermios* old) -{ - unsigned int con; - unsigned int inten; - unsigned int fcon; - unsigned long flags; - unsigned int baud; - unsigned int quot; - - baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16); - quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */ - - switch (termios->c_cflag & CSIZE) { - case CS5: - fcon = WLEN_5; - break; - case CS6: - fcon = WLEN_6; - break; - case CS7: - fcon = WLEN_7; - break; - case CS8: - default: - fcon = WLEN_8; - break; - } - if (termios->c_cflag & CSTOPB) - fcon |= STP2; - if (termios->c_cflag & PARENB) { - fcon |= PEN; - if (!(termios->c_cflag & PARODD)) - fcon |= EPS; - } - if (port->fifosize > 1) - fcon |= FEN; - - spin_lock_irqsave (&port->lock, flags); - - uart_update_timeout (port, termios->c_cflag, baud); - - port->read_status_mask = RxOverrunError; - if (termios->c_iflag & INPCK) - port->read_status_mask |= RxFramingError | RxParityError; - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= RxBreak; - - /* Figure mask for status we ignore */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= RxFramingError | RxParityError; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= RxBreak; - /* Ignore overrun when ignorning parity */ - /* *** FIXME: is this in the right place? */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= RxOverrunError; - } - - /* Ignore all receive errors when receive disabled */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= RxError; - - con = UR (port, UART_R_CON); - inten = (UR (port, UART_R_INTEN) & ~ModemInt); - - if (UART_ENABLE_MS (port, termios->c_cflag)) - inten |= ModemInt; - - BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */ - UR (port, UART_R_INTEN) = 0; /* Disable interrupts */ - UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */ - UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */ - UR (port, UART_R_INTEN) = inten; /* Enable interrupts */ - UR (port, UART_R_CON) = con; /* Restore UART mode */ - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char* lh7a40xuart_type (struct uart_port* port) -{ - return port->type == PORT_LH7A40X ? "LH7A40X" : NULL; -} - -static void lh7a40xuart_release_port (struct uart_port* port) -{ - release_mem_region (port->mapbase, UART_REG_SIZE); -} - -static int lh7a40xuart_request_port (struct uart_port* port) -{ - return request_mem_region (port->mapbase, UART_REG_SIZE, - "serial_lh7a40x") != NULL - ? 0 : -EBUSY; -} - -static void lh7a40xuart_config_port (struct uart_port* port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_LH7A40X; - lh7a40xuart_request_port (port); - } -} - -static int lh7a40xuart_verify_port (struct uart_port* port, - struct serial_struct* ser) -{ - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X) - ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) - ret = -EINVAL; - if (ser->baud_base < 9600) /* *** FIXME: is this true? */ - ret = -EINVAL; - return ret; -} - -static struct uart_ops lh7a40x_uart_ops = { - .tx_empty = lh7a40xuart_tx_empty, - .set_mctrl = lh7a40xuart_set_mctrl, - .get_mctrl = lh7a40xuart_get_mctrl, - .stop_tx = lh7a40xuart_stop_tx, - .start_tx = lh7a40xuart_start_tx, - .stop_rx = lh7a40xuart_stop_rx, - .enable_ms = lh7a40xuart_enable_ms, - .break_ctl = lh7a40xuart_break_ctl, - .startup = lh7a40xuart_startup, - .shutdown = lh7a40xuart_shutdown, - .set_termios = lh7a40xuart_set_termios, - .type = lh7a40xuart_type, - .release_port = lh7a40xuart_release_port, - .request_port = lh7a40xuart_request_port, - .config_port = lh7a40xuart_config_port, - .verify_port = lh7a40xuart_verify_port, -}; - -static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = { - { - .port = { - .membase = (void*) io_p2v (UART1_PHYS), - .mapbase = UART1_PHYS, - .iotype = UPIO_MEM, - .irq = IRQ_UART1INTR, - .uartclk = 14745600/2, - .fifosize = 16, - .ops = &lh7a40x_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - }, - { - .port = { - .membase = (void*) io_p2v (UART2_PHYS), - .mapbase = UART2_PHYS, - .iotype = UPIO_MEM, - .irq = IRQ_UART2INTR, - .uartclk = 14745600/2, - .fifosize = 16, - .ops = &lh7a40x_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - }, - { - .port = { - .membase = (void*) io_p2v (UART3_PHYS), - .mapbase = UART3_PHYS, - .iotype = UPIO_MEM, - .irq = IRQ_UART3INTR, - .uartclk = 14745600/2, - .fifosize = 16, - .ops = &lh7a40x_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - }, -}; - -#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE -# define LH7A40X_CONSOLE NULL -#else -# define LH7A40X_CONSOLE &lh7a40x_console - -static void lh7a40xuart_console_putchar(struct uart_port *port, int ch) -{ - while (UR(port, UART_R_STATUS) & nTxRdy) - ; - UR(port, UART_R_DATA) = ch; -} - -static void lh7a40xuart_console_write (struct console* co, - const char* s, - unsigned int count) -{ - struct uart_port* port = &lh7a40x_ports[co->index].port; - unsigned int con = UR (port, UART_R_CON); - unsigned int inten = UR (port, UART_R_INTEN); - - - UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */ - BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */ - - uart_console_write(port, s, count, lh7a40xuart_console_putchar); - - /* Wait until all characters are sent */ - while (UR (port, UART_R_STATUS) & TxBusy) - ; - - /* Restore control and interrupt mask */ - UR (port, UART_R_CON) = con; - UR (port, UART_R_INTEN) = inten; -} - -static void __init lh7a40xuart_console_get_options (struct uart_port* port, - int* baud, - int* parity, - int* bits) -{ - if (UR (port, UART_R_CON) & UARTEN) { - unsigned int fcon = UR (port, UART_R_FCON); - unsigned int quot = UR (port, UART_R_BRCON) + 1; - - switch (fcon & (PEN | EPS)) { - default: *parity = 'n'; break; - case PEN: *parity = 'o'; break; - case PEN | EPS: *parity = 'e'; break; - } - - switch (fcon & WLEN) { - default: - case WLEN_8: *bits = 8; break; - case WLEN_7: *bits = 7; break; - case WLEN_6: *bits = 6; break; - case WLEN_5: *bits = 5; break; - } - - *baud = port->uartclk/(16*quot); - } -} - -static int __init lh7a40xuart_console_setup (struct console* co, char* options) -{ - struct uart_port* port; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index >= DEV_NR) /* Bounds check on device number */ - co->index = 0; - port = &lh7a40x_ports[co->index].port; - - if (options) - uart_parse_options (options, &baud, &parity, &bits, &flow); - else - lh7a40xuart_console_get_options (port, &baud, &parity, &bits); - - return uart_set_options (port, co, baud, parity, bits, flow); -} - -static struct uart_driver lh7a40x_reg; -static struct console lh7a40x_console = { - .name = "ttyAM", - .write = lh7a40xuart_console_write, - .device = uart_console_device, - .setup = lh7a40xuart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &lh7a40x_reg, -}; - -static int __init lh7a40xuart_console_init(void) -{ - register_console (&lh7a40x_console); - return 0; -} - -console_initcall (lh7a40xuart_console_init); - -#endif - -static struct uart_driver lh7a40x_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyAM", - .dev_name = "ttyAM", - .major = DEV_MAJOR, - .minor = DEV_MINOR, - .nr = DEV_NR, - .cons = LH7A40X_CONSOLE, -}; - -static int __init lh7a40xuart_init(void) -{ - int ret; - - printk (KERN_INFO "serial: LH7A40X serial driver\n"); - - ret = uart_register_driver (&lh7a40x_reg); - - if (ret == 0) { - int i; - - for (i = 0; i < DEV_NR; i++) { - /* UART3, when used, requires GPIO pin reallocation */ - if (lh7a40x_ports[i].port.mapbase == UART3_PHYS) - GPIO_PINMUX |= 1<<3; - uart_add_one_port (&lh7a40x_reg, - &lh7a40x_ports[i].port); - } - } - return ret; -} - -static void __exit lh7a40xuart_exit(void) -{ - int i; - - for (i = 0; i < DEV_NR; i++) - uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port); - - uart_unregister_driver (&lh7a40x_reg); -} - -module_init (lh7a40xuart_init); -module_exit (lh7a40xuart_exit); - -MODULE_AUTHOR ("Marc Singer"); -MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver"); -MODULE_LICENSE ("GPL"); diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index fceea5e4e02f..41b6e51188e4 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -31,7 +31,6 @@ config USB_ARCH_HAS_OHCI # ARM: default y if SA1111 default y if ARCH_OMAP - default y if ARCH_LH7A404 default y if ARCH_S3C2410 default y if PXA27x default y if PXA3xx diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index d50099675f28..e8cbbdac7a15 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -176,18 +176,6 @@ config USB_FSL_USB2 default USB_GADGET select USB_GADGET_SELECTED -config USB_GADGET_LH7A40X - boolean "LH7A40X" - depends on ARCH_LH7A40X - help - This driver provides USB Device Controller driver for LH7A40x - -config USB_LH7A40X - tristate - depends on USB_GADGET_LH7A40X - default USB_GADGET - select USB_GADGET_SELECTED - config USB_GADGET_OMAP boolean "OMAP USB Device Controller" depends on ARCH_OMAP diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 55f5e8ae5924..a2f7f9a4f4a8 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o obj-$(CONFIG_USB_IMX) += imx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o -obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 5c2720d64ffa..e896f6359dfe 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -45,12 +45,6 @@ #define gadget_is_goku(g) 0 #endif -#ifdef CONFIG_USB_GADGET_LH7A40X -#define gadget_is_lh7a40x(g) !strcmp("lh7a40x_udc", (g)->name) -#else -#define gadget_is_lh7a40x(g) 0 -#endif - #ifdef CONFIG_USB_GADGET_OMAP #define gadget_is_omap(g) !strcmp("omap_udc", (g)->name) #else @@ -181,8 +175,6 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x06; else if (gadget_is_omap(gadget)) return 0x08; - else if (gadget_is_lh7a40x(gadget)) - return 0x09; else if (gadget_is_pxa27x(gadget)) return 0x11; else if (gadget_is_s3c2410(gadget)) diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c deleted file mode 100644 index 6b58bd8ce623..000000000000 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ /dev/null @@ -1,2152 +0,0 @@ -/* - * linux/drivers/usb/gadget/lh7a40x_udc.c - * Sharp LH7A40x on-chip full speed USB device controllers - * - * Copyright (C) 2004 Mikko Lahteenmaki, Nordic ID - * Copyright (C) 2004 Bo Henriksen, Nordic ID - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include "lh7a40x_udc.h" - -//#define DEBUG printk -//#define DEBUG_EP0 printk -//#define DEBUG_SETUP printk - -#ifndef DEBUG_EP0 -# define DEBUG_EP0(fmt,args...) -#endif -#ifndef DEBUG_SETUP -# define DEBUG_SETUP(fmt,args...) -#endif -#ifndef DEBUG -# define NO_STATES -# define DEBUG(fmt,args...) -#endif - -#define DRIVER_DESC "LH7A40x USB Device Controller" -#define DRIVER_VERSION __DATE__ - -#ifndef _BIT /* FIXME - what happended to _BIT in 2.6.7bk18? */ -#define _BIT(x) (1<<(x)) -#endif - -struct lh7a40x_udc *the_controller; - -static const char driver_name[] = "lh7a40x_udc"; -static const char driver_desc[] = DRIVER_DESC; -static const char ep0name[] = "ep0-control"; - -/* - Local definintions. -*/ - -#ifndef NO_STATES -static char *state_names[] = { - "WAIT_FOR_SETUP", - "DATA_STATE_XMIT", - "DATA_STATE_NEED_ZLP", - "WAIT_FOR_OUT_STATUS", - "DATA_STATE_RECV" -}; -#endif - -/* - Local declarations. -*/ -static int lh7a40x_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *); -static int lh7a40x_ep_disable(struct usb_ep *ep); -static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t); -static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *); -static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t); -static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *); -static int lh7a40x_set_halt(struct usb_ep *ep, int); -static int lh7a40x_fifo_status(struct usb_ep *ep); -static void lh7a40x_fifo_flush(struct usb_ep *ep); -static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep); -static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr); - -static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, - int status); -static void pio_irq_enable(int bEndpointAddress); -static void pio_irq_disable(int bEndpointAddress); -static void stop_activity(struct lh7a40x_udc *dev, - struct usb_gadget_driver *driver); -static void flush(struct lh7a40x_ep *ep); -static void udc_enable(struct lh7a40x_udc *dev); -static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address); - -static struct usb_ep_ops lh7a40x_ep_ops = { - .enable = lh7a40x_ep_enable, - .disable = lh7a40x_ep_disable, - - .alloc_request = lh7a40x_alloc_request, - .free_request = lh7a40x_free_request, - - .queue = lh7a40x_queue, - .dequeue = lh7a40x_dequeue, - - .set_halt = lh7a40x_set_halt, - .fifo_status = lh7a40x_fifo_status, - .fifo_flush = lh7a40x_fifo_flush, -}; - -/* Inline code */ - -static __inline__ int write_packet(struct lh7a40x_ep *ep, - struct lh7a40x_request *req, int max) -{ - u8 *buf; - int length, count; - volatile u32 *fifo = (volatile u32 *)ep->fifo; - - buf = req->req.buf + req->req.actual; - prefetch(buf); - - length = req->req.length - req->req.actual; - length = min(length, max); - req->req.actual += length; - - DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo); - - count = length; - while (count--) { - *fifo = *buf++; - } - - return length; -} - -static __inline__ void usb_set_index(u32 ep) -{ - *(volatile u32 *)io_p2v(USB_INDEX) = ep; -} - -static __inline__ u32 usb_read(u32 port) -{ - return *(volatile u32 *)io_p2v(port); -} - -static __inline__ void usb_write(u32 val, u32 port) -{ - *(volatile u32 *)io_p2v(port) = val; -} - -static __inline__ void usb_set(u32 val, u32 port) -{ - volatile u32 *ioport = (volatile u32 *)io_p2v(port); - u32 after = (*ioport) | val; - *ioport = after; -} - -static __inline__ void usb_clear(u32 val, u32 port) -{ - volatile u32 *ioport = (volatile u32 *)io_p2v(port); - u32 after = (*ioport) & ~val; - *ioport = after; -} - -/*-------------------------------------------------------------------------*/ - -#define GPIO_PORTC_DR (0x80000E08) -#define GPIO_PORTC_DDR (0x80000E18) -#define GPIO_PORTC_PDR (0x80000E70) - -/* get port C pin data register */ -#define get_portc_pdr(bit) ((usb_read(GPIO_PORTC_PDR) & _BIT(bit)) != 0) -/* get port C data direction register */ -#define get_portc_ddr(bit) ((usb_read(GPIO_PORTC_DDR) & _BIT(bit)) != 0) -/* set port C data register */ -#define set_portc_dr(bit, val) (val ? usb_set(_BIT(bit), GPIO_PORTC_DR) : usb_clear(_BIT(bit), GPIO_PORTC_DR)) -/* set port C data direction register */ -#define set_portc_ddr(bit, val) (val ? usb_set(_BIT(bit), GPIO_PORTC_DDR) : usb_clear(_BIT(bit), GPIO_PORTC_DDR)) - -/* - * LPD7A404 GPIO's: - * Port C bit 1 = USB Port 1 Power Enable - * Port C bit 2 = USB Port 1 Data Carrier Detect - */ -#define is_usb_connected() get_portc_pdr(2) - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -static const char proc_node_name[] = "driver/udc"; - -static int -udc_proc_read(char *page, char **start, off_t off, int count, - int *eof, void *_dev) -{ - char *buf = page; - struct lh7a40x_udc *dev = _dev; - char *next = buf; - unsigned size = count; - unsigned long flags; - int t; - - if (off != 0) - return 0; - - local_irq_save(flags); - - /* basic device status */ - t = scnprintf(next, size, - DRIVER_DESC "\n" - "%s version: %s\n" - "Gadget driver: %s\n" - "Host: %s\n\n", - driver_name, DRIVER_VERSION, - dev->driver ? dev->driver->driver.name : "(none)", - is_usb_connected()? "full speed" : "disconnected"); - size -= t; - next += t; - - t = scnprintf(next, size, - "GPIO:\n" - " Port C bit 1: %d, dir %d\n" - " Port C bit 2: %d, dir %d\n\n", - get_portc_pdr(1), get_portc_ddr(1), - get_portc_pdr(2), get_portc_ddr(2) - ); - size -= t; - next += t; - - t = scnprintf(next, size, - "DCP pullup: %d\n\n", - (usb_read(USB_PM) & PM_USB_DCP) != 0); - size -= t; - next += t; - - local_irq_restore(flags); - *eof = 1; - return count - size; -} - -#define create_proc_files() create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev) -#define remove_proc_files() remove_proc_entry(proc_node_name, NULL) - -#else /* !CONFIG_USB_GADGET_DEBUG_FILES */ - -#define create_proc_files() do {} while (0) -#define remove_proc_files() do {} while (0) - -#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -/* - * udc_disable - disable USB device controller - */ -static void udc_disable(struct lh7a40x_udc *dev) -{ - DEBUG("%s, %p\n", __func__, dev); - - udc_set_address(dev, 0); - - /* Disable interrupts */ - usb_write(0, USB_IN_INT_EN); - usb_write(0, USB_OUT_INT_EN); - usb_write(0, USB_INT_EN); - - /* Disable the USB */ - usb_write(0, USB_PM); - -#ifdef CONFIG_ARCH_LH7A404 - /* Disable USB power */ - set_portc_dr(1, 0); -#endif - - /* if hardware supports it, disconnect from usb */ - /* make_usb_disappear(); */ - - dev->ep0state = WAIT_FOR_SETUP; - dev->gadget.speed = USB_SPEED_UNKNOWN; - dev->usb_address = 0; -} - -/* - * udc_reinit - initialize software state - */ -static void udc_reinit(struct lh7a40x_udc *dev) -{ - u32 i; - - DEBUG("%s, %p\n", __func__, dev); - - /* device/ep0 records init */ - INIT_LIST_HEAD(&dev->gadget.ep_list); - INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); - dev->ep0state = WAIT_FOR_SETUP; - - /* basic endpoint records init */ - for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { - struct lh7a40x_ep *ep = &dev->ep[i]; - - if (i != 0) - list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); - - ep->desc = 0; - ep->stopped = 0; - INIT_LIST_HEAD(&ep->queue); - ep->pio_irqs = 0; - } - - /* the rest was statically initialized, and is read-only */ -} - -#define BYTES2MAXP(x) (x / 8) -#define MAXP2BYTES(x) (x * 8) - -/* until it's enabled, this UDC should be completely invisible - * to any USB host. - */ -static void udc_enable(struct lh7a40x_udc *dev) -{ - int ep; - - DEBUG("%s, %p\n", __func__, dev); - - dev->gadget.speed = USB_SPEED_UNKNOWN; - -#ifdef CONFIG_ARCH_LH7A404 - /* Set Port C bit 1 & 2 as output */ - set_portc_ddr(1, 1); - set_portc_ddr(2, 1); - - /* Enable USB power */ - set_portc_dr(1, 0); -#endif - - /* - * C.f Chapter 18.1.3.1 Initializing the USB - */ - - /* Disable the USB */ - usb_clear(PM_USB_ENABLE, USB_PM); - - /* Reset APB & I/O sides of the USB */ - usb_set(USB_RESET_APB | USB_RESET_IO, USB_RESET); - mdelay(5); - usb_clear(USB_RESET_APB | USB_RESET_IO, USB_RESET); - - /* Set MAXP values for each */ - for (ep = 0; ep < UDC_MAX_ENDPOINTS; ep++) { - struct lh7a40x_ep *ep_reg = &dev->ep[ep]; - u32 csr; - - usb_set_index(ep); - - switch (ep_reg->ep_type) { - case ep_bulk_in: - case ep_interrupt: - usb_clear(USB_IN_CSR2_USB_DMA_EN | USB_IN_CSR2_AUTO_SET, - ep_reg->csr2); - /* Fall through */ - case ep_control: - usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), - USB_IN_MAXP); - break; - case ep_bulk_out: - usb_clear(USB_OUT_CSR2_USB_DMA_EN | - USB_OUT_CSR2_AUTO_CLR, ep_reg->csr2); - usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), - USB_OUT_MAXP); - break; - } - - /* Read & Write CSR1, just in case */ - csr = usb_read(ep_reg->csr1); - usb_write(csr, ep_reg->csr1); - - flush(ep_reg); - } - - /* Disable interrupts */ - usb_write(0, USB_IN_INT_EN); - usb_write(0, USB_OUT_INT_EN); - usb_write(0, USB_INT_EN); - - /* Enable interrupts */ - usb_set(USB_IN_INT_EP0, USB_IN_INT_EN); - usb_set(USB_INT_RESET_INT | USB_INT_RESUME_INT, USB_INT_EN); - /* Dont enable rest of the interrupts */ - /* usb_set(USB_IN_INT_EP3 | USB_IN_INT_EP1 | USB_IN_INT_EP0, USB_IN_INT_EN); - usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); */ - - /* Enable SUSPEND */ - usb_set(PM_ENABLE_SUSPEND, USB_PM); - - /* Enable the USB */ - usb_set(PM_USB_ENABLE, USB_PM); - -#ifdef CONFIG_ARCH_LH7A404 - /* NOTE: DOES NOT WORK! */ - /* Let host detect UDC: - * Software must write a 0 to the PMR:DCP_CTRL bit to turn this - * transistor on and pull the USBDP pin HIGH. - */ - /* usb_clear(PM_USB_DCP, USB_PM); - usb_set(PM_USB_DCP, USB_PM); */ -#endif -} - -/* - Register entry point for the peripheral controller driver. -*/ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct lh7a40x_udc *dev = the_controller; - int retval; - - DEBUG("%s: %s\n", __func__, driver->driver.name); - - if (!driver - || driver->speed != USB_SPEED_FULL - || !bind - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; - - /* first hook up the driver ... */ - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - - device_add(&dev->gadget.dev); - retval = bind(&dev->gadget); - if (retval) { - printk(KERN_WARNING "%s: bind to driver %s --> error %d\n", - dev->gadget.name, driver->driver.name, retval); - device_del(&dev->gadget.dev); - - dev->driver = 0; - dev->gadget.dev.driver = 0; - return retval; - } - - /* ... then enable host detection and ep0; and we're ready - * for set_configuration as well as eventual disconnect. - * NOTE: this shouldn't power up until later. - */ - printk(KERN_WARNING "%s: registered gadget driver '%s'\n", - dev->gadget.name, driver->driver.name); - - udc_enable(dev); - - return 0; -} -EXPORT_SYMBOL(usb_gadget_probe_driver); - -/* - Unregister entry point for the peripheral controller driver. -*/ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct lh7a40x_udc *dev = the_controller; - unsigned long flags; - - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; - - spin_lock_irqsave(&dev->lock, flags); - dev->driver = 0; - stop_activity(dev, driver); - spin_unlock_irqrestore(&dev->lock, flags); - - driver->unbind(&dev->gadget); - dev->gadget.dev.driver = NULL; - device_del(&dev->gadget.dev); - - udc_disable(dev); - - DEBUG("unregistered gadget driver '%s'\n", driver->driver.name); - return 0; -} - -EXPORT_SYMBOL(usb_gadget_unregister_driver); - -/*-------------------------------------------------------------------------*/ - -/** Write request to FIFO (max write == maxp size) - * Return: 0 = still running, 1 = completed, negative = errno - * NOTE: INDEX register must be set for EP - */ -static int write_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req) -{ - u32 max; - u32 csr; - - max = le16_to_cpu(ep->desc->wMaxPacketSize); - - csr = usb_read(ep->csr1); - DEBUG("CSR: %x %d\n", csr, csr & USB_IN_CSR1_FIFO_NOT_EMPTY); - - if (!(csr & USB_IN_CSR1_FIFO_NOT_EMPTY)) { - unsigned count; - int is_last, is_short; - - count = write_packet(ep, req, max); - usb_set(USB_IN_CSR1_IN_PKT_RDY, ep->csr1); - - /* last packet is usually short (or a zlp) */ - if (unlikely(count != max)) - is_last = is_short = 1; - else { - if (likely(req->req.length != req->req.actual) - || req->req.zero) - is_last = 0; - else - is_last = 1; - /* interrupt/iso maxpacket may not fill the fifo */ - is_short = unlikely(max < ep_maxpacket(ep)); - } - - DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __func__, - ep->ep.name, count, - is_last ? "/L" : "", is_short ? "/S" : "", - req->req.length - req->req.actual, req); - - /* requests complete when all IN data is in the FIFO */ - if (is_last) { - done(ep, req, 0); - if (list_empty(&ep->queue)) { - pio_irq_disable(ep_index(ep)); - } - return 1; - } - } else { - DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); - } - - return 0; -} - -/** Read to request from FIFO (max read == bytes in fifo) - * Return: 0 = still running, 1 = completed, negative = errno - * NOTE: INDEX register must be set for EP - */ -static int read_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req) -{ - u32 csr; - u8 *buf; - unsigned bufferspace, count, is_short; - volatile u32 *fifo = (volatile u32 *)ep->fifo; - - /* make sure there's a packet in the FIFO. */ - csr = usb_read(ep->csr1); - if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY)) { - DEBUG("%s: Packet NOT ready!\n", __func__); - return -EINVAL; - } - - buf = req->req.buf + req->req.actual; - prefetchw(buf); - bufferspace = req->req.length - req->req.actual; - - /* read all bytes from this packet */ - count = usb_read(USB_OUT_FIFO_WC1); - req->req.actual += min(count, bufferspace); - - is_short = (count < ep->ep.maxpacket); - DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n", - ep->ep.name, csr, count, - is_short ? "/S" : "", req, req->req.actual, req->req.length); - - while (likely(count-- != 0)) { - u8 byte = (u8) (*fifo & 0xff); - - if (unlikely(bufferspace == 0)) { - /* this happens when the driver's buffer - * is smaller than what the host sent. - * discard the extra data. - */ - if (req->req.status != -EOVERFLOW) - printk(KERN_WARNING "%s overflow %d\n", - ep->ep.name, count); - req->req.status = -EOVERFLOW; - } else { - *buf++ = byte; - bufferspace--; - } - } - - usb_clear(USB_OUT_CSR1_OUT_PKT_RDY, ep->csr1); - - /* completion */ - if (is_short || req->req.actual == req->req.length) { - done(ep, req, 0); - usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); - - if (list_empty(&ep->queue)) - pio_irq_disable(ep_index(ep)); - return 1; - } - - /* finished that packet. the next one may be waiting... */ - return 0; -} - -/* - * done - retire a request; caller blocked irqs - * INDEX register is preserved to keep same - */ -static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, int status) -{ - unsigned int stopped = ep->stopped; - u32 index; - - DEBUG("%s, %p\n", __func__, ep); - list_del_init(&req->queue); - - if (likely(req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - if (status && status != -ESHUTDOWN) - DEBUG("complete %s req %p stat %d len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - /* Read current index (completion may modify it) */ - index = usb_read(USB_INDEX); - - spin_unlock(&ep->dev->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&ep->dev->lock); - - /* Restore index */ - usb_set_index(index); - ep->stopped = stopped; -} - -/** Enable EP interrupt */ -static void pio_irq_enable(int ep) -{ - DEBUG("%s: %d\n", __func__, ep); - - switch (ep) { - case 1: - usb_set(USB_IN_INT_EP1, USB_IN_INT_EN); - break; - case 2: - usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); - break; - case 3: - usb_set(USB_IN_INT_EP3, USB_IN_INT_EN); - break; - default: - DEBUG("Unknown endpoint: %d\n", ep); - break; - } -} - -/** Disable EP interrupt */ -static void pio_irq_disable(int ep) -{ - DEBUG("%s: %d\n", __func__, ep); - - switch (ep) { - case 1: - usb_clear(USB_IN_INT_EP1, USB_IN_INT_EN); - break; - case 2: - usb_clear(USB_OUT_INT_EP2, USB_OUT_INT_EN); - break; - case 3: - usb_clear(USB_IN_INT_EP3, USB_IN_INT_EN); - break; - default: - DEBUG("Unknown endpoint: %d\n", ep); - break; - } -} - -/* - * nuke - dequeue ALL requests - */ -void nuke(struct lh7a40x_ep *ep, int status) -{ - struct lh7a40x_request *req; - - DEBUG("%s, %p\n", __func__, ep); - - /* Flush FIFO */ - flush(ep); - - /* called with irqs blocked */ - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct lh7a40x_request, queue); - done(ep, req, status); - } - - /* Disable IRQ if EP is enabled (has descriptor) */ - if (ep->desc) - pio_irq_disable(ep_index(ep)); -} - -/* -void nuke_all(struct lh7a40x_udc *dev) -{ - int n; - for(n=0; n<UDC_MAX_ENDPOINTS; n++) { - struct lh7a40x_ep *ep = &dev->ep[n]; - usb_set_index(n); - nuke(ep, 0); - } -}*/ - -/* -static void flush_all(struct lh7a40x_udc *dev) -{ - int n; - for (n = 0; n < UDC_MAX_ENDPOINTS; n++) - { - struct lh7a40x_ep *ep = &dev->ep[n]; - flush(ep); - } -} -*/ - -/** Flush EP - * NOTE: INDEX register must be set before this call - */ -static void flush(struct lh7a40x_ep *ep) -{ - DEBUG("%s, %p\n", __func__, ep); - - switch (ep->ep_type) { - case ep_control: - /* check, by implication c.f. 15.1.2.11 */ - break; - - case ep_bulk_in: - case ep_interrupt: - /* if(csr & USB_IN_CSR1_IN_PKT_RDY) */ - usb_set(USB_IN_CSR1_FIFO_FLUSH, ep->csr1); - break; - - case ep_bulk_out: - /* if(csr & USB_OUT_CSR1_OUT_PKT_RDY) */ - usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); - break; - } -} - -/** - * lh7a40x_in_epn - handle IN interrupt - */ -static void lh7a40x_in_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr) -{ - u32 csr; - struct lh7a40x_ep *ep = &dev->ep[ep_idx]; - struct lh7a40x_request *req; - - usb_set_index(ep_idx); - - csr = usb_read(ep->csr1); - DEBUG("%s: %d, csr %x\n", __func__, ep_idx, csr); - - if (csr & USB_IN_CSR1_SENT_STALL) { - DEBUG("USB_IN_CSR1_SENT_STALL\n"); - usb_set(USB_IN_CSR1_SENT_STALL /*|USB_IN_CSR1_SEND_STALL */ , - ep->csr1); - return; - } - - if (!ep->desc) { - DEBUG("%s: NO EP DESC\n", __func__); - return; - } - - if (list_empty(&ep->queue)) - req = 0; - else - req = list_entry(ep->queue.next, struct lh7a40x_request, queue); - - DEBUG("req: %p\n", req); - - if (!req) - return; - - write_fifo(ep, req); -} - -/* ********************************************************************************************* */ -/* Bulk OUT (recv) - */ - -static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr) -{ - struct lh7a40x_ep *ep = &dev->ep[ep_idx]; - struct lh7a40x_request *req; - - DEBUG("%s: %d\n", __func__, ep_idx); - - usb_set_index(ep_idx); - - if (ep->desc) { - u32 csr; - csr = usb_read(ep->csr1); - - while ((csr = - usb_read(ep-> - csr1)) & (USB_OUT_CSR1_OUT_PKT_RDY | - USB_OUT_CSR1_SENT_STALL)) { - DEBUG("%s: %x\n", __func__, csr); - - if (csr & USB_OUT_CSR1_SENT_STALL) { - DEBUG("%s: stall sent, flush fifo\n", - __func__); - /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */ - flush(ep); - } else if (csr & USB_OUT_CSR1_OUT_PKT_RDY) { - if (list_empty(&ep->queue)) - req = 0; - else - req = - list_entry(ep->queue.next, - struct lh7a40x_request, - queue); - - if (!req) { - printk(KERN_WARNING - "%s: NULL REQ %d\n", - __func__, ep_idx); - flush(ep); - break; - } else { - read_fifo(ep, req); - } - } - - } - - } else { - /* Throw packet away.. */ - printk(KERN_WARNING "%s: No descriptor?!?\n", __func__); - flush(ep); - } -} - -static void stop_activity(struct lh7a40x_udc *dev, - struct usb_gadget_driver *driver) -{ - int i; - - /* don't disconnect drivers more than once */ - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = 0; - dev->gadget.speed = USB_SPEED_UNKNOWN; - - /* prevent new request submissions, kill any outstanding requests */ - for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { - struct lh7a40x_ep *ep = &dev->ep[i]; - ep->stopped = 1; - - usb_set_index(i); - nuke(ep, -ESHUTDOWN); - } - - /* report disconnect; the driver is already quiesced */ - if (driver) { - spin_unlock(&dev->lock); - driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - - /* re-init driver-visible data structures */ - udc_reinit(dev); -} - -/** Handle USB RESET interrupt - */ -static void lh7a40x_reset_intr(struct lh7a40x_udc *dev) -{ -#if 0 /* def CONFIG_ARCH_LH7A404 */ - /* Does not work always... */ - - DEBUG("%s: %d\n", __func__, dev->usb_address); - - if (!dev->usb_address) { - /*usb_set(USB_RESET_IO, USB_RESET); - mdelay(5); - usb_clear(USB_RESET_IO, USB_RESET); */ - return; - } - /* Put the USB controller into reset. */ - usb_set(USB_RESET_IO, USB_RESET); - - /* Set Device ID to 0 */ - udc_set_address(dev, 0); - - /* Let PLL2 settle down */ - mdelay(5); - - /* Release the USB controller from reset */ - usb_clear(USB_RESET_IO, USB_RESET); - - /* Re-enable UDC */ - udc_enable(dev); - -#endif - dev->gadget.speed = USB_SPEED_FULL; -} - -/* - * lh7a40x usb client interrupt handler. - */ -static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev) -{ - struct lh7a40x_udc *dev = _dev; - - DEBUG("\n\n"); - - spin_lock(&dev->lock); - - for (;;) { - u32 intr_in = usb_read(USB_IN_INT); - u32 intr_out = usb_read(USB_OUT_INT); - u32 intr_int = usb_read(USB_INT); - - /* Test also against enable bits.. (lh7a40x errata).. Sigh.. */ - u32 in_en = usb_read(USB_IN_INT_EN); - u32 out_en = usb_read(USB_OUT_INT_EN); - - if (!intr_out && !intr_in && !intr_int) - break; - - DEBUG("%s (on state %s)\n", __func__, - state_names[dev->ep0state]); - DEBUG("intr_out = %x\n", intr_out); - DEBUG("intr_in = %x\n", intr_in); - DEBUG("intr_int = %x\n", intr_int); - - if (intr_in) { - usb_write(intr_in, USB_IN_INT); - - if ((intr_in & USB_IN_INT_EP1) - && (in_en & USB_IN_INT_EP1)) { - DEBUG("USB_IN_INT_EP1\n"); - lh7a40x_in_epn(dev, 1, intr_in); - } - if ((intr_in & USB_IN_INT_EP3) - && (in_en & USB_IN_INT_EP3)) { - DEBUG("USB_IN_INT_EP3\n"); - lh7a40x_in_epn(dev, 3, intr_in); - } - if (intr_in & USB_IN_INT_EP0) { - DEBUG("USB_IN_INT_EP0 (control)\n"); - lh7a40x_handle_ep0(dev, intr_in); - } - } - - if (intr_out) { - usb_write(intr_out, USB_OUT_INT); - - if ((intr_out & USB_OUT_INT_EP2) - && (out_en & USB_OUT_INT_EP2)) { - DEBUG("USB_OUT_INT_EP2\n"); - lh7a40x_out_epn(dev, 2, intr_out); - } - } - - if (intr_int) { - usb_write(intr_int, USB_INT); - - if (intr_int & USB_INT_RESET_INT) { - lh7a40x_reset_intr(dev); - } - - if (intr_int & USB_INT_RESUME_INT) { - DEBUG("USB resume\n"); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->resume - && is_usb_connected()) { - dev->driver->resume(&dev->gadget); - } - } - - if (intr_int & USB_INT_SUSPEND_INT) { - DEBUG("USB suspend%s\n", - is_usb_connected()? "" : "+disconnect"); - if (!is_usb_connected()) { - stop_activity(dev, dev->driver); - } else if (dev->gadget.speed != - USB_SPEED_UNKNOWN && dev->driver - && dev->driver->suspend) { - dev->driver->suspend(&dev->gadget); - } - } - - } - } - - spin_unlock(&dev->lock); - - return IRQ_HANDLED; -} - -static int lh7a40x_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct lh7a40x_ep *ep; - struct lh7a40x_udc *dev; - unsigned long flags; - - DEBUG("%s, %p\n", __func__, _ep); - - ep = container_of(_ep, struct lh7a40x_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT - || ep->bEndpointAddress != desc->bEndpointAddress - || ep_maxpacket(ep) < le16_to_cpu(desc->wMaxPacketSize)) { - DEBUG("%s, bad ep or descriptor\n", __func__); - return -EINVAL; - } - - /* xfer types must match, except that interrupt ~= bulk */ - if (ep->bmAttributes != desc->bmAttributes - && ep->bmAttributes != USB_ENDPOINT_XFER_BULK - && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { - DEBUG("%s, %s type mismatch\n", __func__, _ep->name); - return -EINVAL; - } - - /* hardware _could_ do smaller, but driver doesn't */ - if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(ep)) - || !desc->wMaxPacketSize) { - DEBUG("%s, bad %s maxpacket\n", __func__, _ep->name); - return -ERANGE; - } - - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { - DEBUG("%s, bogus device state\n", __func__); - return -ESHUTDOWN; - } - - spin_lock_irqsave(&ep->dev->lock, flags); - - ep->stopped = 0; - ep->desc = desc; - ep->pio_irqs = 0; - ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); - - spin_unlock_irqrestore(&ep->dev->lock, flags); - - /* Reset halt state (does flush) */ - lh7a40x_set_halt(_ep, 0); - - DEBUG("%s: enabled %s\n", __func__, _ep->name); - return 0; -} - -/** Disable EP - * NOTE: Sets INDEX register - */ -static int lh7a40x_ep_disable(struct usb_ep *_ep) -{ - struct lh7a40x_ep *ep; - unsigned long flags; - - DEBUG("%s, %p\n", __func__, _ep); - - ep = container_of(_ep, struct lh7a40x_ep, ep); - if (!_ep || !ep->desc) { - DEBUG("%s, %s not enabled\n", __func__, - _ep ? ep->ep.name : NULL); - return -EINVAL; - } - - spin_lock_irqsave(&ep->dev->lock, flags); - - usb_set_index(ep_index(ep)); - - /* Nuke all pending requests (does flush) */ - nuke(ep, -ESHUTDOWN); - - /* Disable ep IRQ */ - pio_irq_disable(ep_index(ep)); - - ep->desc = 0; - ep->stopped = 1; - - spin_unlock_irqrestore(&ep->dev->lock, flags); - - DEBUG("%s: disabled %s\n", __func__, _ep->name); - return 0; -} - -static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, - gfp_t gfp_flags) -{ - struct lh7a40x_request *req; - - DEBUG("%s, %p\n", __func__, ep); - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return 0; - - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) -{ - struct lh7a40x_request *req; - - DEBUG("%s, %p\n", __func__, ep); - - req = container_of(_req, struct lh7a40x_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -/** Queue one request - * Kickstart transfer if needed - * NOTE: Sets INDEX register - */ -static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct lh7a40x_request *req; - struct lh7a40x_ep *ep; - struct lh7a40x_udc *dev; - unsigned long flags; - - DEBUG("\n\n\n%s, %p\n", __func__, _ep); - - req = container_of(_req, struct lh7a40x_request, req); - if (unlikely - (!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue))) { - DEBUG("%s, bad params\n", __func__); - return -EINVAL; - } - - ep = container_of(_ep, struct lh7a40x_ep, ep); - if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { - DEBUG("%s, bad ep\n", __func__); - return -EINVAL; - } - - dev = ep->dev; - if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { - DEBUG("%s, bogus device state %p\n", __func__, dev->driver); - return -ESHUTDOWN; - } - - DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, - _req->buf); - - spin_lock_irqsave(&dev->lock, flags); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - /* kickstart this i/o queue? */ - DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue), - ep->stopped); - if (list_empty(&ep->queue) && likely(!ep->stopped)) { - u32 csr; - - if (unlikely(ep_index(ep) == 0)) { - /* EP0 */ - list_add_tail(&req->queue, &ep->queue); - lh7a40x_ep0_kick(dev, ep); - req = 0; - } else if (ep_is_in(ep)) { - /* EP1 & EP3 */ - usb_set_index(ep_index(ep)); - csr = usb_read(ep->csr1); - pio_irq_enable(ep_index(ep)); - if ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY) == 0) { - if (write_fifo(ep, req) == 1) - req = 0; - } - } else { - /* EP2 */ - usb_set_index(ep_index(ep)); - csr = usb_read(ep->csr1); - pio_irq_enable(ep_index(ep)); - if (!(csr & USB_OUT_CSR1_FIFO_FULL)) { - if (read_fifo(ep, req) == 1) - req = 0; - } - } - } - - /* pio or dma irq handler advances the queue. */ - if (likely(req != 0)) - list_add_tail(&req->queue, &ep->queue); - - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/* dequeue JUST ONE request */ -static int lh7a40x_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct lh7a40x_ep *ep; - struct lh7a40x_request *req; - unsigned long flags; - - DEBUG("%s, %p\n", __func__, _ep); - - ep = container_of(_ep, struct lh7a40x_ep, ep); - if (!_ep || ep->ep.name == ep0name) - return -EINVAL; - - spin_lock_irqsave(&ep->dev->lock, flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - spin_unlock_irqrestore(&ep->dev->lock, flags); - return -EINVAL; - } - - done(ep, req, -ECONNRESET); - - spin_unlock_irqrestore(&ep->dev->lock, flags); - return 0; -} - -/** Halt specific EP - * Return 0 if success - * NOTE: Sets INDEX register to EP ! - */ -static int lh7a40x_set_halt(struct usb_ep *_ep, int value) -{ - struct lh7a40x_ep *ep; - unsigned long flags; - - ep = container_of(_ep, struct lh7a40x_ep, ep); - if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { - DEBUG("%s, bad ep\n", __func__); - return -EINVAL; - } - - usb_set_index(ep_index(ep)); - - DEBUG("%s, ep %d, val %d\n", __func__, ep_index(ep), value); - - spin_lock_irqsave(&ep->dev->lock, flags); - - if (ep_index(ep) == 0) { - /* EP0 */ - usb_set(EP0_SEND_STALL, ep->csr1); - } else if (ep_is_in(ep)) { - u32 csr = usb_read(ep->csr1); - if (value && ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY) - || !list_empty(&ep->queue))) { - /* - * Attempts to halt IN endpoints will fail (returning -EAGAIN) - * if any transfer requests are still queued, or if the controller - * FIFO still holds bytes that the host hasn't collected. - */ - spin_unlock_irqrestore(&ep->dev->lock, flags); - DEBUG - ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n", - (csr & USB_IN_CSR1_FIFO_NOT_EMPTY), - !list_empty(&ep->queue)); - return -EAGAIN; - } - flush(ep); - if (value) - usb_set(USB_IN_CSR1_SEND_STALL, ep->csr1); - else { - usb_clear(USB_IN_CSR1_SEND_STALL, ep->csr1); - usb_set(USB_IN_CSR1_CLR_DATA_TOGGLE, ep->csr1); - } - - } else { - - flush(ep); - if (value) - usb_set(USB_OUT_CSR1_SEND_STALL, ep->csr1); - else { - usb_clear(USB_OUT_CSR1_SEND_STALL, ep->csr1); - usb_set(USB_OUT_CSR1_CLR_DATA_REG, ep->csr1); - } - } - - if (value) { - ep->stopped = 1; - } else { - ep->stopped = 0; - } - - spin_unlock_irqrestore(&ep->dev->lock, flags); - - DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS"); - - return 0; -} - -/** Return bytes in EP FIFO - * NOTE: Sets INDEX register to EP - */ -static int lh7a40x_fifo_status(struct usb_ep *_ep) -{ - u32 csr; - int count = 0; - struct lh7a40x_ep *ep; - - ep = container_of(_ep, struct lh7a40x_ep, ep); - if (!_ep) { - DEBUG("%s, bad ep\n", __func__); - return -ENODEV; - } - - DEBUG("%s, %d\n", __func__, ep_index(ep)); - - /* LPD can't report unclaimed bytes from IN fifos */ - if (ep_is_in(ep)) - return -EOPNOTSUPP; - - usb_set_index(ep_index(ep)); - - csr = usb_read(ep->csr1); - if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN || - csr & USB_OUT_CSR1_OUT_PKT_RDY) { - count = usb_read(USB_OUT_FIFO_WC1); - } - - return count; -} - -/** Flush EP FIFO - * NOTE: Sets INDEX register to EP - */ -static void lh7a40x_fifo_flush(struct usb_ep *_ep) -{ - struct lh7a40x_ep *ep; - - ep = container_of(_ep, struct lh7a40x_ep, ep); - if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { - DEBUG("%s, bad ep\n", __func__); - return; - } - - usb_set_index(ep_index(ep)); - flush(ep); -} - -/****************************************************************/ -/* End Point 0 related functions */ -/****************************************************************/ - -/* return: 0 = still running, 1 = completed, negative = errno */ -static int write_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req) -{ - u32 max; - unsigned count; - int is_last; - - max = ep_maxpacket(ep); - - DEBUG_EP0("%s\n", __func__); - - count = write_packet(ep, req, max); - - /* last packet is usually short (or a zlp) */ - if (unlikely(count != max)) - is_last = 1; - else { - if (likely(req->req.length != req->req.actual) || req->req.zero) - is_last = 0; - else - is_last = 1; - } - - DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __func__, - ep->ep.name, count, - is_last ? "/L" : "", req->req.length - req->req.actual, req); - - /* requests complete when all IN data is in the FIFO */ - if (is_last) { - done(ep, req, 0); - return 1; - } - - return 0; -} - -static __inline__ int lh7a40x_fifo_read(struct lh7a40x_ep *ep, - unsigned char *cp, int max) -{ - int bytes; - int count = usb_read(USB_OUT_FIFO_WC1); - volatile u32 *fifo = (volatile u32 *)ep->fifo; - - if (count > max) - count = max; - bytes = count; - while (count--) - *cp++ = *fifo & 0xFF; - return bytes; -} - -static __inline__ void lh7a40x_fifo_write(struct lh7a40x_ep *ep, - unsigned char *cp, int count) -{ - volatile u32 *fifo = (volatile u32 *)ep->fifo; - DEBUG_EP0("fifo_write: %d %d\n", ep_index(ep), count); - while (count--) - *fifo = *cp++; -} - -static int read_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req) -{ - u32 csr; - u8 *buf; - unsigned bufferspace, count, is_short; - volatile u32 *fifo = (volatile u32 *)ep->fifo; - - DEBUG_EP0("%s\n", __func__); - - csr = usb_read(USB_EP0_CSR); - if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY)) - return 0; - - buf = req->req.buf + req->req.actual; - prefetchw(buf); - bufferspace = req->req.length - req->req.actual; - - /* read all bytes from this packet */ - if (likely(csr & EP0_OUT_PKT_RDY)) { - count = usb_read(USB_OUT_FIFO_WC1); - req->req.actual += min(count, bufferspace); - } else /* zlp */ - count = 0; - - is_short = (count < ep->ep.maxpacket); - DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n", - ep->ep.name, csr, count, - is_short ? "/S" : "", req, req->req.actual, req->req.length); - - while (likely(count-- != 0)) { - u8 byte = (u8) (*fifo & 0xff); - - if (unlikely(bufferspace == 0)) { - /* this happens when the driver's buffer - * is smaller than what the host sent. - * discard the extra data. - */ - if (req->req.status != -EOVERFLOW) - DEBUG_EP0("%s overflow %d\n", ep->ep.name, - count); - req->req.status = -EOVERFLOW; - } else { - *buf++ = byte; - bufferspace--; - } - } - - /* completion */ - if (is_short || req->req.actual == req->req.length) { - done(ep, req, 0); - return 1; - } - - /* finished that packet. the next one may be waiting... */ - return 0; -} - -/** - * udc_set_address - set the USB address for this device - * @address: - * - * Called from control endpoint function after it decodes a set address setup packet. - */ -static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address) -{ - DEBUG_EP0("%s: %d\n", __func__, address); - /* c.f. 15.1.2.2 Table 15-4 address will be used after DATA_END is set */ - dev->usb_address = address; - usb_set((address & USB_FA_FUNCTION_ADDR), USB_FA); - usb_set(USB_FA_ADDR_UPDATE | (address & USB_FA_FUNCTION_ADDR), USB_FA); - /* usb_read(USB_FA); */ -} - -/* - * DATA_STATE_RECV (OUT_PKT_RDY) - * - if error - * set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits - * - else - * set EP0_CLR_OUT bit - if last set EP0_DATA_END bit - */ -static void lh7a40x_ep0_out(struct lh7a40x_udc *dev, u32 csr) -{ - struct lh7a40x_request *req; - struct lh7a40x_ep *ep = &dev->ep[0]; - int ret; - - DEBUG_EP0("%s: %x\n", __func__, csr); - - if (list_empty(&ep->queue)) - req = 0; - else - req = list_entry(ep->queue.next, struct lh7a40x_request, queue); - - if (req) { - - if (req->req.length == 0) { - DEBUG_EP0("ZERO LENGTH OUT!\n"); - usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR); - dev->ep0state = WAIT_FOR_SETUP; - return; - } - ret = read_fifo_ep0(ep, req); - if (ret) { - /* Done! */ - DEBUG_EP0("%s: finished, waiting for status\n", - __func__); - - usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR); - dev->ep0state = WAIT_FOR_SETUP; - } else { - /* Not done yet.. */ - DEBUG_EP0("%s: not finished\n", __func__); - usb_set(EP0_CLR_OUT, USB_EP0_CSR); - } - } else { - DEBUG_EP0("NO REQ??!\n"); - } -} - -/* - * DATA_STATE_XMIT - */ -static int lh7a40x_ep0_in(struct lh7a40x_udc *dev, u32 csr) -{ - struct lh7a40x_request *req; - struct lh7a40x_ep *ep = &dev->ep[0]; - int ret, need_zlp = 0; - - DEBUG_EP0("%s: %x\n", __func__, csr); - - if (list_empty(&ep->queue)) - req = 0; - else - req = list_entry(ep->queue.next, struct lh7a40x_request, queue); - - if (!req) { - DEBUG_EP0("%s: NULL REQ\n", __func__); - return 0; - } - - if (req->req.length == 0) { - - usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); - dev->ep0state = WAIT_FOR_SETUP; - return 1; - } - - if (req->req.length - req->req.actual == EP0_PACKETSIZE) { - /* Next write will end with the packet size, */ - /* so we need Zero-length-packet */ - need_zlp = 1; - } - - ret = write_fifo_ep0(ep, req); - - if (ret == 1 && !need_zlp) { - /* Last packet */ - DEBUG_EP0("%s: finished, waiting for status\n", __func__); - - usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); - dev->ep0state = WAIT_FOR_SETUP; - } else { - DEBUG_EP0("%s: not finished\n", __func__); - usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR); - } - - if (need_zlp) { - DEBUG_EP0("%s: Need ZLP!\n", __func__); - usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR); - dev->ep0state = DATA_STATE_NEED_ZLP; - } - - return 1; -} - -static int lh7a40x_handle_get_status(struct lh7a40x_udc *dev, - struct usb_ctrlrequest *ctrl) -{ - struct lh7a40x_ep *ep0 = &dev->ep[0]; - struct lh7a40x_ep *qep; - int reqtype = (ctrl->bRequestType & USB_RECIP_MASK); - u16 val = 0; - - if (reqtype == USB_RECIP_INTERFACE) { - /* This is not supported. - * And according to the USB spec, this one does nothing.. - * Just return 0 - */ - DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n"); - } else if (reqtype == USB_RECIP_DEVICE) { - DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n"); - val |= (1 << 0); /* Self powered */ - /*val |= (1<<1); *//* Remote wakeup */ - } else if (reqtype == USB_RECIP_ENDPOINT) { - int ep_num = (ctrl->wIndex & ~USB_DIR_IN); - - DEBUG_SETUP - ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n", - ep_num, ctrl->wLength); - - if (ctrl->wLength > 2 || ep_num > 3) - return -EOPNOTSUPP; - - qep = &dev->ep[ep_num]; - if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0) - && ep_index(qep) != 0) { - return -EOPNOTSUPP; - } - - usb_set_index(ep_index(qep)); - - /* Return status on next IN token */ - switch (qep->ep_type) { - case ep_control: - val = - (usb_read(qep->csr1) & EP0_SEND_STALL) == - EP0_SEND_STALL; - break; - case ep_bulk_in: - case ep_interrupt: - val = - (usb_read(qep->csr1) & USB_IN_CSR1_SEND_STALL) == - USB_IN_CSR1_SEND_STALL; - break; - case ep_bulk_out: - val = - (usb_read(qep->csr1) & USB_OUT_CSR1_SEND_STALL) == - USB_OUT_CSR1_SEND_STALL; - break; - } - - /* Back to EP0 index */ - usb_set_index(0); - - DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num, - ctrl->wIndex, val); - } else { - DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype); - return -EOPNOTSUPP; - } - - /* Clear "out packet ready" */ - usb_set((EP0_CLR_OUT), USB_EP0_CSR); - /* Put status to FIFO */ - lh7a40x_fifo_write(ep0, (u8 *) & val, sizeof(val)); - /* Issue "In packet ready" */ - usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); - - return 0; -} - -/* - * WAIT_FOR_SETUP (OUT_PKT_RDY) - * - read data packet from EP0 FIFO - * - decode command - * - if error - * set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits - * - else - * set EP0_CLR_OUT | EP0_DATA_END bits - */ -static void lh7a40x_ep0_setup(struct lh7a40x_udc *dev, u32 csr) -{ - struct lh7a40x_ep *ep = &dev->ep[0]; - struct usb_ctrlrequest ctrl; - int i, bytes, is_in; - - DEBUG_SETUP("%s: %x\n", __func__, csr); - - /* Nuke all previous transfers */ - nuke(ep, -EPROTO); - - /* read control req from fifo (8 bytes) */ - bytes = lh7a40x_fifo_read(ep, (unsigned char *)&ctrl, 8); - - DEBUG_SETUP("Read CTRL REQ %d bytes\n", bytes); - DEBUG_SETUP("CTRL.bRequestType = %d (is_in %d)\n", ctrl.bRequestType, - ctrl.bRequestType == USB_DIR_IN); - DEBUG_SETUP("CTRL.bRequest = %d\n", ctrl.bRequest); - DEBUG_SETUP("CTRL.wLength = %d\n", ctrl.wLength); - DEBUG_SETUP("CTRL.wValue = %d (%d)\n", ctrl.wValue, ctrl.wValue >> 8); - DEBUG_SETUP("CTRL.wIndex = %d\n", ctrl.wIndex); - - /* Set direction of EP0 */ - if (likely(ctrl.bRequestType & USB_DIR_IN)) { - ep->bEndpointAddress |= USB_DIR_IN; - is_in = 1; - } else { - ep->bEndpointAddress &= ~USB_DIR_IN; - is_in = 0; - } - - dev->req_pending = 1; - - /* Handle some SETUP packets ourselves */ - switch (ctrl.bRequest) { - case USB_REQ_SET_ADDRESS: - if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) - break; - - DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue); - udc_set_address(dev, ctrl.wValue); - usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR); - return; - - case USB_REQ_GET_STATUS:{ - if (lh7a40x_handle_get_status(dev, &ctrl) == 0) - return; - - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - if (ctrl.bRequestType == USB_RECIP_ENDPOINT) { - struct lh7a40x_ep *qep; - int ep_num = (ctrl.wIndex & 0x0f); - - /* Support only HALT feature */ - if (ctrl.wValue != 0 || ctrl.wLength != 0 - || ep_num > 3 || ep_num < 1) - break; - - qep = &dev->ep[ep_num]; - spin_unlock(&dev->lock); - if (ctrl.bRequest == USB_REQ_SET_FEATURE) { - DEBUG_SETUP("SET_FEATURE (%d)\n", - ep_num); - lh7a40x_set_halt(&qep->ep, 1); - } else { - DEBUG_SETUP("CLR_FEATURE (%d)\n", - ep_num); - lh7a40x_set_halt(&qep->ep, 0); - } - spin_lock(&dev->lock); - usb_set_index(0); - - /* Reply with a ZLP on next IN token */ - usb_set((EP0_CLR_OUT | EP0_DATA_END), - USB_EP0_CSR); - return; - } - break; - } - - default: - break; - } - - if (likely(dev->driver)) { - /* device-2-host (IN) or no data setup command, process immediately */ - spin_unlock(&dev->lock); - i = dev->driver->setup(&dev->gadget, &ctrl); - spin_lock(&dev->lock); - - if (i < 0) { - /* setup processing failed, force stall */ - DEBUG_SETUP - (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n", - i); - usb_set_index(0); - usb_set((EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL), - USB_EP0_CSR); - - /* ep->stopped = 1; */ - dev->ep0state = WAIT_FOR_SETUP; - } - } -} - -/* - * DATA_STATE_NEED_ZLP - */ -static void lh7a40x_ep0_in_zlp(struct lh7a40x_udc *dev, u32 csr) -{ - DEBUG_EP0("%s: %x\n", __func__, csr); - - /* c.f. Table 15-14 */ - usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR); - dev->ep0state = WAIT_FOR_SETUP; -} - -/* - * handle ep0 interrupt - */ -static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr) -{ - struct lh7a40x_ep *ep = &dev->ep[0]; - u32 csr; - - /* Set index 0 */ - usb_set_index(0); - csr = usb_read(USB_EP0_CSR); - - DEBUG_EP0("%s: csr = %x\n", __func__, csr); - - /* - * For overview of what we should be doing see c.f. Chapter 18.1.2.4 - * We will follow that outline here modified by our own global state - * indication which provides hints as to what we think should be - * happening.. - */ - - /* - * if SENT_STALL is set - * - clear the SENT_STALL bit - */ - if (csr & EP0_SENT_STALL) { - DEBUG_EP0("%s: EP0_SENT_STALL is set: %x\n", __func__, csr); - usb_clear((EP0_SENT_STALL | EP0_SEND_STALL), USB_EP0_CSR); - nuke(ep, -ECONNABORTED); - dev->ep0state = WAIT_FOR_SETUP; - return; - } - - /* - * if a transfer is in progress && IN_PKT_RDY and OUT_PKT_RDY are clear - * - fill EP0 FIFO - * - if last packet - * - set IN_PKT_RDY | DATA_END - * - else - * set IN_PKT_RDY - */ - if (!(csr & (EP0_IN_PKT_RDY | EP0_OUT_PKT_RDY))) { - DEBUG_EP0("%s: IN_PKT_RDY and OUT_PKT_RDY are clear\n", - __func__); - - switch (dev->ep0state) { - case DATA_STATE_XMIT: - DEBUG_EP0("continue with DATA_STATE_XMIT\n"); - lh7a40x_ep0_in(dev, csr); - return; - case DATA_STATE_NEED_ZLP: - DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n"); - lh7a40x_ep0_in_zlp(dev, csr); - return; - default: - /* Stall? */ - DEBUG_EP0("Odd state!! state = %s\n", - state_names[dev->ep0state]); - dev->ep0state = WAIT_FOR_SETUP; - /* nuke(ep, 0); */ - /* usb_set(EP0_SEND_STALL, ep->csr1); */ - break; - } - } - - /* - * if SETUP_END is set - * - abort the last transfer - * - set SERVICED_SETUP_END_BIT - */ - if (csr & EP0_SETUP_END) { - DEBUG_EP0("%s: EP0_SETUP_END is set: %x\n", __func__, csr); - - usb_set(EP0_CLR_SETUP_END, USB_EP0_CSR); - - nuke(ep, 0); - dev->ep0state = WAIT_FOR_SETUP; - } - - /* - * if EP0_OUT_PKT_RDY is set - * - read data packet from EP0 FIFO - * - decode command - * - if error - * set SERVICED_OUT_PKT_RDY | DATA_END bits | SEND_STALL - * - else - * set SERVICED_OUT_PKT_RDY | DATA_END bits - */ - if (csr & EP0_OUT_PKT_RDY) { - - DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __func__, - csr); - - switch (dev->ep0state) { - case WAIT_FOR_SETUP: - DEBUG_EP0("WAIT_FOR_SETUP\n"); - lh7a40x_ep0_setup(dev, csr); - break; - - case DATA_STATE_RECV: - DEBUG_EP0("DATA_STATE_RECV\n"); - lh7a40x_ep0_out(dev, csr); - break; - - default: - /* send stall? */ - DEBUG_EP0("strange state!! 2. send stall? state = %d\n", - dev->ep0state); - break; - } - } -} - -static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep) -{ - u32 csr; - - usb_set_index(0); - csr = usb_read(USB_EP0_CSR); - - DEBUG_EP0("%s: %x\n", __func__, csr); - - /* Clear "out packet ready" */ - usb_set(EP0_CLR_OUT, USB_EP0_CSR); - - if (ep_is_in(ep)) { - dev->ep0state = DATA_STATE_XMIT; - lh7a40x_ep0_in(dev, csr); - } else { - dev->ep0state = DATA_STATE_RECV; - lh7a40x_ep0_out(dev, csr); - } -} - -/* --------------------------------------------------------------------------- - * device-scoped parts of the api to the usb controller hardware - * --------------------------------------------------------------------------- - */ - -static int lh7a40x_udc_get_frame(struct usb_gadget *_gadget) -{ - u32 frame1 = usb_read(USB_FRM_NUM1); /* Least significant 8 bits */ - u32 frame2 = usb_read(USB_FRM_NUM2); /* Most significant 3 bits */ - DEBUG("%s, %p\n", __func__, _gadget); - return ((frame2 & 0x07) << 8) | (frame1 & 0xff); -} - -static int lh7a40x_udc_wakeup(struct usb_gadget *_gadget) -{ - /* host may not have enabled remote wakeup */ - /*if ((UDCCS0 & UDCCS0_DRWF) == 0) - return -EHOSTUNREACH; - udc_set_mask_UDCCR(UDCCR_RSM); */ - return -ENOTSUPP; -} - -static const struct usb_gadget_ops lh7a40x_udc_ops = { - .get_frame = lh7a40x_udc_get_frame, - .wakeup = lh7a40x_udc_wakeup, - /* current versions must always be self-powered */ -}; - -static void nop_release(struct device *dev) -{ - DEBUG("%s %s\n", __func__, dev_name(dev)); -} - -static struct lh7a40x_udc memory = { - .usb_address = 0, - - .gadget = { - .ops = &lh7a40x_udc_ops, - .ep0 = &memory.ep[0].ep, - .name = driver_name, - .dev = { - .init_name = "gadget", - .release = nop_release, - }, - }, - - /* control endpoint */ - .ep[0] = { - .ep = { - .name = ep0name, - .ops = &lh7a40x_ep_ops, - .maxpacket = EP0_PACKETSIZE, - }, - .dev = &memory, - - .bEndpointAddress = 0, - .bmAttributes = 0, - - .ep_type = ep_control, - .fifo = io_p2v(USB_EP0_FIFO), - .csr1 = USB_EP0_CSR, - .csr2 = USB_EP0_CSR, - }, - - /* first group of endpoints */ - .ep[1] = { - .ep = { - .name = "ep1in-bulk", - .ops = &lh7a40x_ep_ops, - .maxpacket = 64, - }, - .dev = &memory, - - .bEndpointAddress = USB_DIR_IN | 1, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - - .ep_type = ep_bulk_in, - .fifo = io_p2v(USB_EP1_FIFO), - .csr1 = USB_IN_CSR1, - .csr2 = USB_IN_CSR2, - }, - - .ep[2] = { - .ep = { - .name = "ep2out-bulk", - .ops = &lh7a40x_ep_ops, - .maxpacket = 64, - }, - .dev = &memory, - - .bEndpointAddress = 2, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - - .ep_type = ep_bulk_out, - .fifo = io_p2v(USB_EP2_FIFO), - .csr1 = USB_OUT_CSR1, - .csr2 = USB_OUT_CSR2, - }, - - .ep[3] = { - .ep = { - .name = "ep3in-int", - .ops = &lh7a40x_ep_ops, - .maxpacket = 64, - }, - .dev = &memory, - - .bEndpointAddress = USB_DIR_IN | 3, - .bmAttributes = USB_ENDPOINT_XFER_INT, - - .ep_type = ep_interrupt, - .fifo = io_p2v(USB_EP3_FIFO), - .csr1 = USB_IN_CSR1, - .csr2 = USB_IN_CSR2, - }, -}; - -/* - * probe - binds to the platform device - */ -static int lh7a40x_udc_probe(struct platform_device *pdev) -{ - struct lh7a40x_udc *dev = &memory; - int retval; - - DEBUG("%s: %p\n", __func__, pdev); - - spin_lock_init(&dev->lock); - dev->dev = &pdev->dev; - - device_initialize(&dev->gadget.dev); - dev->gadget.dev.parent = &pdev->dev; - - the_controller = dev; - platform_set_drvdata(pdev, dev); - - udc_disable(dev); - udc_reinit(dev); - - /* irq setup after old hardware state is cleaned up */ - retval = - request_irq(IRQ_USBINTR, lh7a40x_udc_irq, IRQF_DISABLED, driver_name, - dev); - if (retval != 0) { - DEBUG(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, - IRQ_USBINTR, retval); - return -EBUSY; - } - - create_proc_files(); - - return retval; -} - -static int lh7a40x_udc_remove(struct platform_device *pdev) -{ - struct lh7a40x_udc *dev = platform_get_drvdata(pdev); - - DEBUG("%s: %p\n", __func__, pdev); - - if (dev->driver) - return -EBUSY; - - udc_disable(dev); - remove_proc_files(); - - free_irq(IRQ_USBINTR, dev); - - platform_set_drvdata(pdev, 0); - - the_controller = 0; - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static struct platform_driver udc_driver = { - .probe = lh7a40x_udc_probe, - .remove = lh7a40x_udc_remove, - /* FIXME power management support */ - /* .suspend = ... disable UDC */ - /* .resume = ... re-enable UDC */ - .driver = { - .name = (char *)driver_name, - .owner = THIS_MODULE, - }, -}; - -static int __init udc_init(void) -{ - DEBUG("%s: %s version %s\n", __func__, driver_name, DRIVER_VERSION); - return platform_driver_register(&udc_driver); -} - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} - -module_init(udc_init); -module_exit(udc_exit); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Mikko Lahteenmaki, Bo Henriksen"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:lh7a40x_udc"); diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h deleted file mode 100644 index ca861203a301..000000000000 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * linux/drivers/usb/gadget/lh7a40x_udc.h - * Sharp LH7A40x on-chip full speed USB device controllers - * - * Copyright (C) 2004 Mikko Lahteenmaki, Nordic ID - * Copyright (C) 2004 Bo Henriksen, Nordic ID - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __LH7A40X_H_ -#define __LH7A40X_H_ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> -#include <linux/proc_fs.h> -#include <linux/mm.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> - -#include <asm/byteorder.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/unaligned.h> -#include <mach/hardware.h> - -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - -/* - * Memory map - */ - -#define USB_FA 0x80000200 // function address register -#define USB_PM 0x80000204 // power management register - -#define USB_IN_INT 0x80000208 // IN interrupt register bank (EP0-EP3) -#define USB_OUT_INT 0x80000210 // OUT interrupt register bank (EP2) -#define USB_INT 0x80000218 // interrupt register bank - -#define USB_IN_INT_EN 0x8000021C // IN interrupt enable register bank -#define USB_OUT_INT_EN 0x80000224 // OUT interrupt enable register bank -#define USB_INT_EN 0x8000022C // USB interrupt enable register bank - -#define USB_FRM_NUM1 0x80000230 // Frame number1 register -#define USB_FRM_NUM2 0x80000234 // Frame number2 register -#define USB_INDEX 0x80000238 // index register - -#define USB_IN_MAXP 0x80000240 // IN MAXP register -#define USB_IN_CSR1 0x80000244 // IN CSR1 register/EP0 CSR register -#define USB_EP0_CSR 0x80000244 // IN CSR1 register/EP0 CSR register -#define USB_IN_CSR2 0x80000248 // IN CSR2 register -#define USB_OUT_MAXP 0x8000024C // OUT MAXP register - -#define USB_OUT_CSR1 0x80000250 // OUT CSR1 register -#define USB_OUT_CSR2 0x80000254 // OUT CSR2 register -#define USB_OUT_FIFO_WC1 0x80000258 // OUT FIFO write count1 register -#define USB_OUT_FIFO_WC2 0x8000025C // OUT FIFO write count2 register - -#define USB_RESET 0x8000044C // USB reset register - -#define USB_EP0_FIFO 0x80000280 -#define USB_EP1_FIFO 0x80000284 -#define USB_EP2_FIFO 0x80000288 -#define USB_EP3_FIFO 0x8000028c - -/* - * USB reset register - */ -#define USB_RESET_APB (1<<1) //resets USB APB control side WRITE -#define USB_RESET_IO (1<<0) //resets USB IO side WRITE - -/* - * USB function address register - */ -#define USB_FA_ADDR_UPDATE (1<<7) -#define USB_FA_FUNCTION_ADDR (0x7F) - -/* - * Power Management register - */ -#define PM_USB_DCP (1<<5) -#define PM_USB_ENABLE (1<<4) -#define PM_USB_RESET (1<<3) -#define PM_UC_RESUME (1<<2) -#define PM_SUSPEND_MODE (1<<1) -#define PM_ENABLE_SUSPEND (1<<0) - -/* - * IN interrupt register - */ -#define USB_IN_INT_EP3 (1<<3) -#define USB_IN_INT_EP1 (1<<1) -#define USB_IN_INT_EP0 (1<<0) - -/* - * OUT interrupt register - */ -#define USB_OUT_INT_EP2 (1<<2) - -/* - * USB interrupt register - */ -#define USB_INT_RESET_INT (1<<2) -#define USB_INT_RESUME_INT (1<<1) -#define USB_INT_SUSPEND_INT (1<<0) - -/* - * USB interrupt enable register - */ -#define USB_INT_EN_USB_RESET_INTER (1<<2) -#define USB_INT_EN_RESUME_INTER (1<<1) -#define USB_INT_EN_SUSPEND_INTER (1<<0) - -/* - * INCSR1 register - */ -#define USB_IN_CSR1_CLR_DATA_TOGGLE (1<<6) -#define USB_IN_CSR1_SENT_STALL (1<<5) -#define USB_IN_CSR1_SEND_STALL (1<<4) -#define USB_IN_CSR1_FIFO_FLUSH (1<<3) -#define USB_IN_CSR1_FIFO_NOT_EMPTY (1<<1) -#define USB_IN_CSR1_IN_PKT_RDY (1<<0) - -/* - * INCSR2 register - */ -#define USB_IN_CSR2_AUTO_SET (1<<7) -#define USB_IN_CSR2_USB_DMA_EN (1<<4) - -/* - * OUT CSR1 register - */ -#define USB_OUT_CSR1_CLR_DATA_REG (1<<7) -#define USB_OUT_CSR1_SENT_STALL (1<<6) -#define USB_OUT_CSR1_SEND_STALL (1<<5) -#define USB_OUT_CSR1_FIFO_FLUSH (1<<4) -#define USB_OUT_CSR1_FIFO_FULL (1<<1) -#define USB_OUT_CSR1_OUT_PKT_RDY (1<<0) - -/* - * OUT CSR2 register - */ -#define USB_OUT_CSR2_AUTO_CLR (1<<7) -#define USB_OUT_CSR2_USB_DMA_EN (1<<4) - -/* - * EP0 CSR - */ -#define EP0_CLR_SETUP_END (1<<7) /* Clear "Setup Ends" Bit (w) */ -#define EP0_CLR_OUT (1<<6) /* Clear "Out packet ready" Bit (w) */ -#define EP0_SEND_STALL (1<<5) /* Send STALL Handshake (rw) */ -#define EP0_SETUP_END (1<<4) /* Setup Ends (r) */ - -#define EP0_DATA_END (1<<3) /* Data end (rw) */ -#define EP0_SENT_STALL (1<<2) /* Sent Stall Handshake (r) */ -#define EP0_IN_PKT_RDY (1<<1) /* In packet ready (rw) */ -#define EP0_OUT_PKT_RDY (1<<0) /* Out packet ready (r) */ - -/* general CSR */ -#define OUT_PKT_RDY (1<<0) -#define IN_PKT_RDY (1<<0) - -/* - * IN/OUT MAXP register - */ -#define USB_OUT_MAXP_MAXP (0xF) -#define USB_IN_MAXP_MAXP (0xF) - -// Max packet size -//#define EP0_PACKETSIZE 0x10 -#define EP0_PACKETSIZE 0x8 -#define EP0_MAXPACKETSIZE 0x10 - -#define UDC_MAX_ENDPOINTS 4 - -#define WAIT_FOR_SETUP 0 -#define DATA_STATE_XMIT 1 -#define DATA_STATE_NEED_ZLP 2 -#define WAIT_FOR_OUT_STATUS 3 -#define DATA_STATE_RECV 4 - -/* ********************************************************************************************* */ -/* IO - */ - -typedef enum ep_type { - ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt -} ep_type_t; - -struct lh7a40x_ep { - struct usb_ep ep; - struct lh7a40x_udc *dev; - - const struct usb_endpoint_descriptor *desc; - struct list_head queue; - unsigned long pio_irqs; - - u8 stopped; - u8 bEndpointAddress; - u8 bmAttributes; - - ep_type_t ep_type; - u32 fifo; - u32 csr1; - u32 csr2; -}; - -struct lh7a40x_request { - struct usb_request req; - struct list_head queue; -}; - -struct lh7a40x_udc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct device *dev; - spinlock_t lock; - - int ep0state; - struct lh7a40x_ep ep[UDC_MAX_ENDPOINTS]; - - unsigned char usb_address; - - unsigned req_pending:1, req_std:1, req_config:1; -}; - -extern struct lh7a40x_udc *the_controller; - -#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN)==USB_DIR_IN) -#define ep_index(EP) ((EP)->bEndpointAddress&0xF) -#define ep_maxpacket(EP) ((EP)->ep.maxpacket) - -#endif diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 759a12ff8048..b426c1e8a679 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1023,11 +1023,6 @@ MODULE_LICENSE ("GPL"); #define OMAP3_PLATFORM_DRIVER ohci_hcd_omap3_driver #endif -#ifdef CONFIG_ARCH_LH7A404 -#include "ohci-lh7a404.c" -#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver -#endif - #if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) #include "ohci-pxa27x.c" #define PLATFORM_DRIVER ohci_hcd_pxa27x_driver diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c deleted file mode 100644 index 18d39f0463ee..000000000000 --- a/drivers/usb/host/ohci-lh7a404.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * (C) Copyright 2002 Hewlett-Packard Company - * - * Bus Glue for Sharp LH7A404 - * - * Written by Christopher Hoover <ch@hpl.hp.com> - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - * by Durgesh Pattamatta <pattamattad@sharpsec.com> - * - * This file is licenced under the GPL. - */ - -#include <linux/platform_device.h> -#include <linux/signal.h> - -#include <mach/hardware.h> - - -extern int usb_disabled(void); - -/*-------------------------------------------------------------------------*/ - -static void lh7a404_start_hc(struct platform_device *dev) -{ - printk(KERN_DEBUG "%s: starting LH7A404 OHCI USB Controller\n", - __FILE__); - - /* - * Now, carefully enable the USB clock, and take - * the USB host controller out of reset. - */ - CSC_PWRCNT |= CSC_PWRCNT_USBH_EN; /* Enable clock */ - udelay(1000); - USBH_CMDSTATUS = OHCI_HCR; - - printk(KERN_DEBUG "%s: Clock to USB host has been enabled \n", __FILE__); -} - -static void lh7a404_stop_hc(struct platform_device *dev) -{ - printk(KERN_DEBUG "%s: stopping LH7A404 OHCI USB Controller\n", - __FILE__); - - CSC_PWRCNT &= ~CSC_PWRCNT_USBH_EN; /* Disable clock */ -} - - -/*-------------------------------------------------------------------------*/ - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - - -/** - * usb_hcd_lh7a404_probe - initialize LH7A404-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - */ -int usb_hcd_lh7a404_probe (const struct hc_driver *driver, - struct platform_device *dev) -{ - int retval; - struct usb_hcd *hcd; - - if (dev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ"); - return -ENOMEM; - } - - hcd = usb_create_hcd(driver, &dev->dev, "lh7a404"); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = dev->resource[0].start; - hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed"); - retval = -ENOMEM; - goto err2; - } - - lh7a404_start_hc(dev); - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED); - if (retval == 0) - return retval; - - lh7a404_stop_hc(dev); - iounmap(hcd->regs); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: - usb_put_hcd(hcd); - return retval; -} - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_lh7a404_remove - shutdown processing for LH7A404-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_lh7a404_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - */ -void usb_hcd_lh7a404_remove (struct usb_hcd *hcd, struct platform_device *dev) -{ - usb_remove_hcd(hcd); - lh7a404_stop_hc(dev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -/*-------------------------------------------------------------------------*/ - -static int __devinit -ohci_lh7a404_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - ohci_dbg (ohci, "ohci_lh7a404_start, ohci:%p", ohci); - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run (ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); - ohci_stop (hcd); - return ret; - } - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_lh7a404_hc_driver = { - .description = hcd_name, - .product_desc = "LH7A404 OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_lh7a404_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_lh7a404_drv_probe(struct platform_device *pdev) -{ - int ret; - - pr_debug ("In ohci_hcd_lh7a404_drv_probe"); - - if (usb_disabled()) - return -ENODEV; - - ret = usb_hcd_lh7a404_probe(&ohci_lh7a404_hc_driver, pdev); - return ret; -} - -static int ohci_hcd_lh7a404_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_lh7a404_remove(hcd, pdev); - return 0; -} - /*TBD*/ -/*static int ohci_hcd_lh7a404_drv_suspend(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - return 0; -} -static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - - return 0; -} -*/ - -static struct platform_driver ohci_hcd_lh7a404_driver = { - .probe = ohci_hcd_lh7a404_drv_probe, - .remove = ohci_hcd_lh7a404_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - /*.suspend = ohci_hcd_lh7a404_drv_suspend, */ - /*.resume = ohci_hcd_lh7a404_drv_resume, */ - .driver = { - .name = "lh7a404-ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:lh7a404-ohci"); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 51facb985c84..04812b42fe6f 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -575,18 +575,8 @@ static inline void _ohci_writel (const struct ohci_hcd *ohci, #endif } -#ifdef CONFIG_ARCH_LH7A404 -/* Marc Singer: at the time this code was written, the LH7A404 - * had a problem reading the USB host registers. This - * implementation of the ohci_readl function performs the read - * twice as a work-around. - */ -#define ohci_readl(o,r) (_ohci_readl(o,r),_ohci_readl(o,r)) -#define ohci_writel(o,v,r) _ohci_writel(o,v,r) -#else #define ohci_readl(o,r) _ohci_readl(o,r) #define ohci_writel(o,v,r) _ohci_writel(o,v,r) -#endif /*-------------------------------------------------------------------------*/ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6bafb51bb437..8334f05cb8c5 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -322,69 +322,6 @@ config FB_ARMCLCD here and read <file:Documentation/kbuild/modules.txt>. The module will be called amba-clcd. -choice - - depends on FB_ARMCLCD && (ARCH_LH7A40X || ARCH_LH7952X) - prompt "LCD Panel" - default FB_ARMCLCD_SHARP_LQ035Q7DB02 - -config FB_ARMCLCD_SHARP_LQ035Q7DB02_HRTFT - bool "LogicPD LCD 3.5\" QVGA w/HRTFT IC" - help - This is an implementation of the Sharp LQ035Q7DB02, a 3.5" - color QVGA, HRTFT panel. The LogicPD device includes - an integrated HRTFT controller IC. - The native resolution is 240x320. - -config FB_ARMCLCD_SHARP_LQ057Q3DC02 - bool "LogicPD LCD 5.7\" QVGA" - help - This is an implementation of the Sharp LQ057Q3DC02, a 5.7" - color QVGA, TFT panel. The LogicPD device includes an - The native resolution is 320x240. - -config FB_ARMCLCD_SHARP_LQ64D343 - bool "LogicPD LCD 6.4\" VGA" - help - This is an implementation of the Sharp LQ64D343, a 6.4" - color VGA, TFT panel. The LogicPD device includes an - The native resolution is 640x480. - -config FB_ARMCLCD_SHARP_LQ10D368 - bool "LogicPD LCD 10.4\" VGA" - help - This is an implementation of the Sharp LQ10D368, a 10.4" - color VGA, TFT panel. The LogicPD device includes an - The native resolution is 640x480. - - -config FB_ARMCLCD_SHARP_LQ121S1DG41 - bool "LogicPD LCD 12.1\" SVGA" - help - This is an implementation of the Sharp LQ121S1DG41, a 12.1" - color SVGA, TFT panel. The LogicPD device includes an - The native resolution is 800x600. - - This panel requires a clock rate may be an integer fraction - of the base LCDCLK frequency. The driver will select the - highest frequency available that is lower than the maximum - allowed. The panel may flicker if the clock rate is - slower than the recommended minimum. - -config FB_ARMCLCD_AUO_A070VW01_WIDE - bool "AU Optronics A070VW01 LCD 7.0\" WIDE" - help - This is an implementation of the AU Optronics, a 7.0" - WIDE Color. The native resolution is 234x480. - -config FB_ARMCLCD_HITACHI - bool "Hitachi Wide Screen 800x480" - help - This is an implementation of the Hitachi 800x480. - -endchoice - - config FB_ACORN bool "Acorn VIDC support" depends on (FB = y) && ARM && ARCH_ACORN @@ -439,6 +376,24 @@ config FB_CYBER2000 Say Y if you have a NetWinder or a graphics card containing this device, otherwise say N. +config FB_CYBER2000_DDC + bool "DDC for CyberPro support" + depends on FB_CYBER2000 + select FB_DDC + default y + help + Say Y here if you want DDC support for your CyberPro graphics + card. This is only I2C bus support, driver does not use EDID. + +config FB_CYBER2000_I2C + bool "CyberPro 2000/2010/5000 I2C support" + depends on FB_CYBER2000 && I2C && ARCH_NETWINDER + select I2C_ALGOBIT + help + Enable support for the I2C video decoder interface on the + Integraphics CyberPro 20x0 and 5000 VGA chips. This is used + on the Netwinder machines for the SAA7111 video capture. + config FB_APOLLO bool depends on (FB = y) && APOLLO diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 1c2c68356ea7..5fc983c5b92c 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -120,8 +120,23 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) static int clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) { + u32 caps; int ret = 0; + if (fb->panel->caps && fb->board->caps) + caps = fb->panel->caps & fb->board->caps; + else { + /* Old way of specifying what can be used */ + caps = fb->panel->cntl & CNTL_BGR ? + CLCD_CAP_BGR : CLCD_CAP_RGB; + /* But mask out 444 modes as they weren't supported */ + caps &= ~CLCD_CAP_444; + } + + /* Only TFT panels can do RGB888/BGR888 */ + if (!(fb->panel->cntl & CNTL_LCDTFT)) + caps &= ~CLCD_CAP_888; + memset(&var->transp, 0, sizeof(var->transp)); var->red.msb_right = 0; @@ -133,6 +148,13 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) case 2: case 4: case 8: + /* If we can't do 5551, reject */ + caps &= CLCD_CAP_5551; + if (!caps) { + ret = -EINVAL; + break; + } + var->red.length = var->bits_per_pixel; var->red.offset = 0; var->green.length = var->bits_per_pixel; @@ -140,23 +162,61 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) var->blue.length = var->bits_per_pixel; var->blue.offset = 0; break; + case 16: - var->red.length = 5; - var->blue.length = 5; + /* If we can't do 444, 5551 or 565, reject */ + if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) { + ret = -EINVAL; + break; + } + /* - * Green length can be 5 or 6 depending whether - * we're operating in RGB555 or RGB565 mode. + * Green length can be 4, 5 or 6 depending whether + * we're operating in 444, 5551 or 565 mode. */ - if (var->green.length != 5 && var->green.length != 6) - var->green.length = 6; + if (var->green.length == 4 && caps & CLCD_CAP_444) + caps &= CLCD_CAP_444; + if (var->green.length == 5 && caps & CLCD_CAP_5551) + caps &= CLCD_CAP_5551; + else if (var->green.length == 6 && caps & CLCD_CAP_565) + caps &= CLCD_CAP_565; + else { + /* + * PL110 officially only supports RGB555, + * but may be wired up to allow RGB565. + */ + if (caps & CLCD_CAP_565) { + var->green.length = 6; + caps &= CLCD_CAP_565; + } else if (caps & CLCD_CAP_5551) { + var->green.length = 5; + caps &= CLCD_CAP_5551; + } else { + var->green.length = 4; + caps &= CLCD_CAP_444; + } + } + + if (var->green.length >= 5) { + var->red.length = 5; + var->blue.length = 5; + } else { + var->red.length = 4; + var->blue.length = 4; + } break; case 32: - if (fb->panel->cntl & CNTL_LCDTFT) { - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; + /* If we can't do 888, reject */ + caps &= CLCD_CAP_888; + if (!caps) { + ret = -EINVAL; break; } + + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; default: ret = -EINVAL; break; @@ -168,7 +228,20 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) * the bitfield length defined above. */ if (ret == 0 && var->bits_per_pixel >= 16) { - if (fb->panel->cntl & CNTL_BGR) { + bool bgr, rgb; + + bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0; + rgb = caps & CLCD_CAP_RGB && var->red.offset == 0; + + if (!bgr && !rgb) + /* + * The requested format was not possible, try just + * our capabilities. One of BGR or RGB must be + * supported. + */ + bgr = caps & CLCD_CAP_BGR; + + if (bgr) { var->blue.offset = 0; var->green.offset = var->blue.offset + var->blue.length; var->red.offset = var->green.offset + var->green.length; @@ -443,8 +516,8 @@ static int clcdfb_register(struct clcd_fb *fb) fb_set_var(&fb->fb, &fb->fb.var); - printk(KERN_INFO "CLCD: %s hardware, %s display\n", - fb->board->name, fb->panel->mode.name); + dev_info(&fb->dev->dev, "%s hardware, %s display\n", + fb->board->name, fb->panel->mode.name); ret = register_framebuffer(&fb->fb); if (ret == 0) @@ -461,7 +534,7 @@ static int clcdfb_register(struct clcd_fb *fb) return ret; } -static int clcdfb_probe(struct amba_device *dev, struct amba_id *id) +static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id) { struct clcd_board *board = dev->dev.platform_data; struct clcd_fb *fb; @@ -486,6 +559,10 @@ static int clcdfb_probe(struct amba_device *dev, struct amba_id *id) fb->dev = dev; fb->board = board; + dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n", + amba_part(dev), amba_rev(dev), + (unsigned long long)dev->res.start); + ret = fb->board->setup(fb); if (ret) goto free_fb; diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 0c1afd13ddd3..850380795b05 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -47,6 +47,8 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> #include <asm/pgtable.h> #include <asm/system.h> @@ -61,10 +63,10 @@ struct cfb_info { struct fb_info fb; struct display_switch *dispsw; struct display *display; - struct pci_dev *dev; unsigned char __iomem *region; unsigned char __iomem *regs; u_int id; + u_int irq; int func_use_count; u_long ref_ps; @@ -88,6 +90,19 @@ struct cfb_info { u_char ramdac_powerdown; u32 pseudo_palette[16]; + + spinlock_t reg_b0_lock; + +#ifdef CONFIG_FB_CYBER2000_DDC + bool ddc_registered; + struct i2c_adapter ddc_adapter; + struct i2c_algo_bit_data ddc_algo; +#endif + +#ifdef CONFIG_FB_CYBER2000_I2C + struct i2c_adapter i2c_adapter; + struct i2c_algo_bit_data i2c_algo; +#endif }; static char *default_font = "Acorn8x8"; @@ -494,6 +509,7 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) cyber2000_attrw(0x14, 0x00, cfb); /* PLL registers */ + spin_lock(&cfb->reg_b0_lock); cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb); cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb); cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb); @@ -501,6 +517,7 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) cyber2000_grphw(0x90, 0x01, cfb); cyber2000_grphw(0xb9, 0x80, cfb); cyber2000_grphw(0xb9, 0x00, cfb); + spin_unlock(&cfb->reg_b0_lock); cfb->ramdac_ctrl = hw->ramdac; cyber2000fb_write_ramdac_ctrl(cfb); @@ -681,9 +698,9 @@ cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb, * pll_ps_calc = best_div1 / (ref_ps * best_mult) */ best_diff = 0x7fffffff; - best_mult = 32; - best_div1 = 255; - for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) { + best_mult = 2; + best_div1 = 32; + for (t_div1 = 2; t_div1 < 32; t_div1 += 1) { u_int rr, t_mult, t_pll_ps; int diff; @@ -1105,24 +1122,22 @@ void cyber2000fb_disable_extregs(struct cfb_info *cfb) } EXPORT_SYMBOL(cyber2000fb_disable_extregs); -void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var) -{ - memcpy(var, &cfb->fb.var, sizeof(struct fb_var_screeninfo)); -} -EXPORT_SYMBOL(cyber2000fb_get_fb_var); - /* * Attach a capture/tv driver to the core CyberX0X0 driver. */ int cyber2000fb_attach(struct cyberpro_info *info, int idx) { if (int_cfb_info != NULL) { - info->dev = int_cfb_info->dev; + info->dev = int_cfb_info->fb.device; +#ifdef CONFIG_FB_CYBER2000_I2C + info->i2c = &int_cfb_info->i2c_adapter; +#else + info->i2c = NULL; +#endif info->regs = int_cfb_info->regs; + info->irq = int_cfb_info->irq; info->fb = int_cfb_info->fb.screen_base; info->fb_size = int_cfb_info->fb.fix.smem_len; - info->enable_extregs = cyber2000fb_enable_extregs; - info->disable_extregs = cyber2000fb_disable_extregs; info->info = int_cfb_info; strlcpy(info->dev_name, int_cfb_info->fb.fix.id, @@ -1141,6 +1156,183 @@ void cyber2000fb_detach(int idx) } EXPORT_SYMBOL(cyber2000fb_detach); +#ifdef CONFIG_FB_CYBER2000_DDC + +#define DDC_REG 0xb0 +#define DDC_SCL_OUT (1 << 0) +#define DDC_SDA_OUT (1 << 4) +#define DDC_SCL_IN (1 << 2) +#define DDC_SDA_IN (1 << 6) + +static void cyber2000fb_enable_ddc(struct cfb_info *cfb) +{ + spin_lock(&cfb->reg_b0_lock); + cyber2000fb_writew(0x1bf, 0x3ce, cfb); +} + +static void cyber2000fb_disable_ddc(struct cfb_info *cfb) +{ + cyber2000fb_writew(0x0bf, 0x3ce, cfb); + spin_unlock(&cfb->reg_b0_lock); +} + + +static void cyber2000fb_ddc_setscl(void *data, int val) +{ + struct cfb_info *cfb = data; + unsigned char reg; + + cyber2000fb_enable_ddc(cfb); + reg = cyber2000_grphr(DDC_REG, cfb); + if (!val) /* bit is inverted */ + reg |= DDC_SCL_OUT; + else + reg &= ~DDC_SCL_OUT; + cyber2000_grphw(DDC_REG, reg, cfb); + cyber2000fb_disable_ddc(cfb); +} + +static void cyber2000fb_ddc_setsda(void *data, int val) +{ + struct cfb_info *cfb = data; + unsigned char reg; + + cyber2000fb_enable_ddc(cfb); + reg = cyber2000_grphr(DDC_REG, cfb); + if (!val) /* bit is inverted */ + reg |= DDC_SDA_OUT; + else + reg &= ~DDC_SDA_OUT; + cyber2000_grphw(DDC_REG, reg, cfb); + cyber2000fb_disable_ddc(cfb); +} + +static int cyber2000fb_ddc_getscl(void *data) +{ + struct cfb_info *cfb = data; + int retval; + + cyber2000fb_enable_ddc(cfb); + retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN); + cyber2000fb_disable_ddc(cfb); + + return retval; +} + +static int cyber2000fb_ddc_getsda(void *data) +{ + struct cfb_info *cfb = data; + int retval; + + cyber2000fb_enable_ddc(cfb); + retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN); + cyber2000fb_disable_ddc(cfb); + + return retval; +} + +static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb) +{ + strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id, + sizeof(cfb->ddc_adapter.name)); + cfb->ddc_adapter.owner = THIS_MODULE; + cfb->ddc_adapter.class = I2C_CLASS_DDC; + cfb->ddc_adapter.algo_data = &cfb->ddc_algo; + cfb->ddc_adapter.dev.parent = cfb->fb.device; + cfb->ddc_algo.setsda = cyber2000fb_ddc_setsda; + cfb->ddc_algo.setscl = cyber2000fb_ddc_setscl; + cfb->ddc_algo.getsda = cyber2000fb_ddc_getsda; + cfb->ddc_algo.getscl = cyber2000fb_ddc_getscl; + cfb->ddc_algo.udelay = 10; + cfb->ddc_algo.timeout = 20; + cfb->ddc_algo.data = cfb; + + i2c_set_adapdata(&cfb->ddc_adapter, cfb); + + return i2c_bit_add_bus(&cfb->ddc_adapter); +} +#endif /* CONFIG_FB_CYBER2000_DDC */ + +#ifdef CONFIG_FB_CYBER2000_I2C +static void cyber2000fb_i2c_setsda(void *data, int state) +{ + struct cfb_info *cfb = data; + unsigned int latch2; + + spin_lock(&cfb->reg_b0_lock); + latch2 = cyber2000_grphr(EXT_LATCH2, cfb); + latch2 &= EXT_LATCH2_I2C_CLKEN; + if (state) + latch2 |= EXT_LATCH2_I2C_DATEN; + cyber2000_grphw(EXT_LATCH2, latch2, cfb); + spin_unlock(&cfb->reg_b0_lock); +} + +static void cyber2000fb_i2c_setscl(void *data, int state) +{ + struct cfb_info *cfb = data; + unsigned int latch2; + + spin_lock(&cfb->reg_b0_lock); + latch2 = cyber2000_grphr(EXT_LATCH2, cfb); + latch2 &= EXT_LATCH2_I2C_DATEN; + if (state) + latch2 |= EXT_LATCH2_I2C_CLKEN; + cyber2000_grphw(EXT_LATCH2, latch2, cfb); + spin_unlock(&cfb->reg_b0_lock); +} + +static int cyber2000fb_i2c_getsda(void *data) +{ + struct cfb_info *cfb = data; + int ret; + + spin_lock(&cfb->reg_b0_lock); + ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_DAT); + spin_unlock(&cfb->reg_b0_lock); + + return ret; +} + +static int cyber2000fb_i2c_getscl(void *data) +{ + struct cfb_info *cfb = data; + int ret; + + spin_lock(&cfb->reg_b0_lock); + ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_CLK); + spin_unlock(&cfb->reg_b0_lock); + + return ret; +} + +static int __devinit cyber2000fb_i2c_register(struct cfb_info *cfb) +{ + strlcpy(cfb->i2c_adapter.name, cfb->fb.fix.id, + sizeof(cfb->i2c_adapter.name)); + cfb->i2c_adapter.owner = THIS_MODULE; + cfb->i2c_adapter.algo_data = &cfb->i2c_algo; + cfb->i2c_adapter.dev.parent = cfb->fb.device; + cfb->i2c_algo.setsda = cyber2000fb_i2c_setsda; + cfb->i2c_algo.setscl = cyber2000fb_i2c_setscl; + cfb->i2c_algo.getsda = cyber2000fb_i2c_getsda; + cfb->i2c_algo.getscl = cyber2000fb_i2c_getscl; + cfb->i2c_algo.udelay = 5; + cfb->i2c_algo.timeout = msecs_to_jiffies(100); + cfb->i2c_algo.data = cfb; + + return i2c_bit_add_bus(&cfb->i2c_adapter); +} + +static void cyber2000fb_i2c_unregister(struct cfb_info *cfb) +{ + i2c_del_adapter(&cfb->i2c_adapter); +} +#else +#define cyber2000fb_i2c_register(cfb) (0) +#define cyber2000fb_i2c_unregister(cfb) do { } while (0) +#endif + /* * These parameters give * 640x480, hsync 31.5kHz, vsync 60Hz @@ -1275,6 +1467,8 @@ static struct cfb_info __devinit *cyberpro_alloc_fb_info(unsigned int id, cfb->fb.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; cfb->fb.pseudo_palette = cfb->pseudo_palette; + spin_lock_init(&cfb->reg_b0_lock); + fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0); return cfb; @@ -1369,6 +1563,11 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb) cfb->fb.fix.mmio_len = MMIO_SIZE; cfb->fb.screen_base = cfb->region; +#ifdef CONFIG_FB_CYBER2000_DDC + if (cyber2000fb_setup_ddc_bus(cfb) == 0) + cfb->ddc_registered = true; +#endif + err = -EINVAL; if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0, &cyber2000fb_default_mode, 8)) { @@ -1401,14 +1600,32 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb) cfb->fb.var.xres, cfb->fb.var.yres, h_sync / 1000, h_sync % 1000, v_sync); - if (cfb->dev) - cfb->fb.device = &cfb->dev->dev; + err = cyber2000fb_i2c_register(cfb); + if (err) + goto failed; + err = register_framebuffer(&cfb->fb); + if (err) + cyber2000fb_i2c_unregister(cfb); failed: +#ifdef CONFIG_FB_CYBER2000_DDC + if (err && cfb->ddc_registered) + i2c_del_adapter(&cfb->ddc_adapter); +#endif return err; } +static void __devexit cyberpro_common_remove(struct cfb_info *cfb) +{ + unregister_framebuffer(&cfb->fb); +#ifdef CONFIG_FB_CYBER2000_DDC + if (cfb->ddc_registered) + i2c_del_adapter(&cfb->ddc_adapter); +#endif + cyber2000fb_i2c_unregister(cfb); +} + static void cyberpro_common_resume(struct cfb_info *cfb) { cyberpro_init_hw(cfb); @@ -1442,12 +1659,13 @@ static int __devinit cyberpro_vl_probe(void) if (!cfb) goto failed_release; - cfb->dev = NULL; + cfb->irq = -1; cfb->region = ioremap(FB_START, FB_SIZE); if (!cfb->region) goto failed_ioremap; cfb->regs = cfb->region + MMIO_OFFSET; + cfb->fb.device = NULL; cfb->fb.fix.mmio_start = FB_START + MMIO_OFFSET; cfb->fb.fix.smem_start = FB_START; @@ -1585,12 +1803,13 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (err) goto failed_regions; - cfb->dev = dev; + cfb->irq = dev->irq; cfb->region = pci_ioremap_bar(dev, 0); if (!cfb->region) goto failed_ioremap; cfb->regs = cfb->region + MMIO_OFFSET; + cfb->fb.device = &dev->dev; cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET; cfb->fb.fix.smem_start = pci_resource_start(dev, 0); @@ -1648,15 +1867,7 @@ static void __devexit cyberpro_pci_remove(struct pci_dev *dev) struct cfb_info *cfb = pci_get_drvdata(dev); if (cfb) { - /* - * If unregister_framebuffer fails, then - * we will be leaving hooks that could cause - * oopsen laying around. - */ - if (unregister_framebuffer(&cfb->fb)) - printk(KERN_WARNING "%s: danger Will Robinson, " - "danger danger! Oopsen imminent!\n", - cfb->fb.fix.id); + cyberpro_common_remove(cfb); iounmap(cfb->region); cyberpro_free_fb_info(cfb); diff --git a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h index de4fc43e51c1..bad69102e774 100644 --- a/drivers/video/cyber2000fb.h +++ b/drivers/video/cyber2000fb.h @@ -464,12 +464,14 @@ static void debug_printf(char *fmt, ...) struct cfb_info; struct cyberpro_info { - struct pci_dev *dev; + struct device *dev; + struct i2c_adapter *i2c; unsigned char __iomem *regs; char __iomem *fb; char dev_name[32]; unsigned int fb_size; unsigned int chip_id; + unsigned int irq; /* * The following is a pointer to be passed into the @@ -478,15 +480,6 @@ struct cyberpro_info { * is within this structure. */ struct cfb_info *info; - - /* - * Use these to enable the BM or TV registers. In an SMP - * environment, these two function pointers should only be - * called from the module_init() or module_exit() - * functions. - */ - void (*enable_extregs)(struct cfb_info *); - void (*disable_extregs)(struct cfb_info *); }; #define ID_IGA_1682 0 @@ -494,8 +487,6 @@ struct cyberpro_info { #define ID_CYBERPRO_2010 2 #define ID_CYBERPRO_5000 3 -struct fb_var_screeninfo; - /* * Note! Writing to the Cyber20x0 registers from an interrupt * routine is definitely a bad idea atm. @@ -504,4 +495,3 @@ int cyber2000fb_attach(struct cyberpro_info *info, int idx); void cyber2000fb_detach(int idx); void cyber2000fb_enable_extregs(struct cfb_info *cfb); void cyber2000fb_disable_extregs(struct cfb_info *cfb); -void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var); diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index 9127eda2145b..0a0efe713bc8 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -278,7 +278,7 @@ static struct miscdevice sp805_wdt_miscdev = { }; static int __devinit -sp805_wdt_probe(struct amba_device *adev, struct amba_id *id) +sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; |