Commit aae528d9 authored by Russell King's avatar Russell King

Merge branches 'acorn', 'ebsa110' and 'sa11x0' into platforms

......@@ -759,6 +759,7 @@ config ARCH_SA1100
select ARCH_REQUIRE_GPIOLIB
select HAVE_IDE
select NEED_MACH_MEMORY_H
select SPARSE_IRQ
help
Support for StrongARM 11x0 based boards.
......
......@@ -16,6 +16,7 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/errno.h>
......@@ -28,9 +29,8 @@
#include <linux/io.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/mach-types.h>
#include <asm/sizes.h>
#include <asm/hardware/sa1111.h>
......@@ -86,8 +86,10 @@
#define IRQ_S1_CD_VALID (52)
#define IRQ_S0_BVD1_STSCHG (53)
#define IRQ_S1_BVD1_STSCHG (54)
#define SA1111_IRQ_NR (55)
extern void __init sa1110_mb_enable(void);
extern void sa1110_mb_enable(void);
extern void sa1110_mb_disable(void);
/*
* We keep the following data for the overall SA1111. Note that the
......@@ -104,6 +106,7 @@ struct sa1111 {
int irq_base; /* base for cascaded on-chip IRQs */
spinlock_t lock;
void __iomem *base;
struct sa1111_platform_data *pdata;
#ifdef CONFIG_PM
void *saved_state;
#endif
......@@ -118,6 +121,7 @@ static struct sa1111 *g_sa1111;
struct sa1111_dev_info {
unsigned long offset;
unsigned long skpcr_mask;
bool dma;
unsigned int devid;
unsigned int irq[6];
};
......@@ -126,6 +130,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
{
.offset = SA1111_USB,
.skpcr_mask = SKPCR_UCLKEN,
.dma = true,
.devid = SA1111_DEVID_USB,
.irq = {
IRQ_USBPWR,
......@@ -139,6 +144,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
{
.offset = 0x0600,
.skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
.dma = true,
.devid = SA1111_DEVID_SAC,
.irq = {
AUDXMTDMADONEA,
......@@ -155,7 +161,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
{
.offset = SA1111_KBD,
.skpcr_mask = SKPCR_PTCLKEN,
.devid = SA1111_DEVID_PS2,
.devid = SA1111_DEVID_PS2_KBD,
.irq = {
IRQ_TPRXINT,
IRQ_TPTXINT
......@@ -164,7 +170,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
{
.offset = SA1111_MSE,
.skpcr_mask = SKPCR_PMCLKEN,
.devid = SA1111_DEVID_PS2,
.devid = SA1111_DEVID_PS2_MSE,
.irq = {
IRQ_MSRXINT,
IRQ_MSTXINT
......@@ -434,16 +440,28 @@ static struct irq_chip sa1111_high_chip = {
.irq_set_wake = sa1111_wake_highirq,
};
static void sa1111_setup_irq(struct sa1111 *sachip)
static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base)
{
void __iomem *irqbase = sachip->base + SA1111_INTC;
unsigned int irq;
unsigned i, irq;
int ret;
/*
* We're guaranteed that this region hasn't been taken.
*/
request_mem_region(sachip->phys + SA1111_INTC, 512, "irq");
ret = irq_alloc_descs(-1, irq_base, SA1111_IRQ_NR, -1);
if (ret <= 0) {
dev_err(sachip->dev, "unable to allocate %u irqs: %d\n",
SA1111_IRQ_NR, ret);
if (ret == 0)
ret = -EINVAL;
return ret;
}
sachip->irq_base = ret;
/* disable all IRQs */
sa1111_writel(0, irqbase + SA1111_INTEN0);
sa1111_writel(0, irqbase + SA1111_INTEN1);
......@@ -463,14 +481,16 @@ static void sa1111_setup_irq(struct sa1111 *sachip)
sa1111_writel(~0, irqbase + SA1111_INTSTATCLR0);
sa1111_writel(~0, irqbase + SA1111_INTSTATCLR1);
for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
for (i = IRQ_GPAIN0; i <= SSPROR; i++) {
irq = sachip->irq_base + i;
irq_set_chip_and_handler(irq, &sa1111_low_chip,
handle_edge_irq);
irq_set_chip_data(irq, sachip);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) {
for (i = AUDXMTDMADONEA; i <= IRQ_S1_BVD1_STSCHG; i++) {
irq = sachip->irq_base + i;
irq_set_chip_and_handler(irq, &sa1111_high_chip,
handle_edge_irq);
irq_set_chip_data(irq, sachip);
......@@ -483,6 +503,11 @@ static void sa1111_setup_irq(struct sa1111 *sachip)
irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING);
irq_set_handler_data(sachip->irq, sachip);
irq_set_chained_handler(sachip->irq, sa1111_irq_handler);
dev_info(sachip->dev, "Providing IRQ%u-%u\n",
sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1);
return 0;
}
/*
......@@ -581,41 +606,10 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
}
#endif
#ifdef CONFIG_DMABOUNCE
/*
* According to the "Intel StrongARM SA-1111 Microprocessor Companion
* Chip Specification Update" (June 2000), erratum #7, there is a
* significant bug in the SA1111 SDRAM shared memory controller. If
* an access to a region of memory above 1MB relative to the bank base,
* it is important that address bit 10 _NOT_ be asserted. Depending
* on the configuration of the RAM, bit 10 may correspond to one
* of several different (processor-relative) address bits.
*
* This routine only identifies whether or not a given DMA address
* is susceptible to the bug.
*
* This should only get called for sa1111_device types due to the
* way we configure our device dma_masks.
*/
static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
{
/*
* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
* User's Guide" mentions that jumpers R51 and R52 control the
* target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
* SDRAM bank 1 on Neponset). The default configuration selects
* Assabet, so any address in bank 1 is necessarily invalid.
*/
return (machine_is_assabet() || machine_is_pfs168()) &&
(addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
}
#endif
static void sa1111_dev_release(struct device *_dev)
{
struct sa1111_dev *dev = SA1111_DEV(_dev);
release_resource(&dev->res);
kfree(dev);
}
......@@ -624,67 +618,58 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
struct sa1111_dev_info *info)
{
struct sa1111_dev *dev;
unsigned i;
int ret;
dev = kzalloc(sizeof(struct sa1111_dev), GFP_KERNEL);
if (!dev) {
ret = -ENOMEM;
goto out;
goto err_alloc;
}
device_initialize(&dev->dev);
dev_set_name(&dev->dev, "%4.4lx", info->offset);
dev->devid = info->devid;
dev->dev.parent = sachip->dev;
dev->dev.bus = &sa1111_bus_type;
dev->dev.release = sa1111_dev_release;
dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
dev->res.start = sachip->phys + info->offset;
dev->res.end = dev->res.start + 511;
dev->res.name = dev_name(&dev->dev);
dev->res.flags = IORESOURCE_MEM;
dev->mapbase = sachip->base + info->offset;
dev->skpcr_mask = info->skpcr_mask;
memmove(dev->irq, info->irq, sizeof(dev->irq));
ret = request_resource(parent, &dev->res);
if (ret) {
printk("SA1111: failed to allocate resource for %s\n",
dev->res.name);
dev_set_name(&dev->dev, NULL);
kfree(dev);
goto out;
}
for (i = 0; i < ARRAY_SIZE(info->irq); i++)
dev->irq[i] = sachip->irq_base + info->irq[i];
ret = device_register(&dev->dev);
if (ret) {
release_resource(&dev->res);
kfree(dev);
goto out;
}
#ifdef CONFIG_DMABOUNCE
/*
* If the parent device has a DMA mask associated with it,
* propagate it down to the children.
* If the parent device has a DMA mask associated with it, and
* this child supports DMA, propagate it down to the children.
*/
if (sachip->dev->dma_mask) {
if (info->dma && sachip->dev->dma_mask) {
dev->dma_mask = *sachip->dev->dma_mask;
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
}
if (dev->dma_mask != 0xffffffffUL) {
ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
sa1111_needs_bounce);
ret = request_resource(parent, &dev->res);
if (ret) {
dev_err(&dev->dev, "SA1111: Failed to register"
" with dmabounce\n");
device_unregister(&dev->dev);
}
}
dev_err(sachip->dev, "failed to allocate resource for %s\n",
dev->res.name);
goto err_resource;
}
#endif
out:
ret = device_add(&dev->dev);
if (ret)
goto err_add;
return 0;
err_add:
release_resource(&dev->res);
err_resource:
put_device(&dev->dev);
err_alloc:
return ret;
}
......@@ -698,16 +683,21 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
* Returns:
* %-ENODEV device not found.
* %-EBUSY physical address already marked in-use.
* %-EINVAL no platform data passed
* %0 successful.
*/
static int __devinit
__sa1111_probe(struct device *me, struct resource *mem, int irq)
{
struct sa1111_platform_data *pd = me->platform_data;
struct sa1111 *sachip;
unsigned long id;
unsigned int has_devs;
int i, ret = -ENODEV;
if (!pd)
return -EINVAL;
sachip = kzalloc(sizeof(struct sa1111), GFP_KERNEL);
if (!sachip)
return -ENOMEM;
......@@ -727,6 +717,7 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
sachip->dev = me;
dev_set_drvdata(sachip->dev, sachip);
sachip->pdata = pd;
sachip->phys = mem->start;
sachip->irq = irq;
......@@ -759,6 +750,16 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
*/
sa1111_wake(sachip);
/*
* The interrupt controller must be initialised before any
* other device to ensure that the interrupts are available.
*/
if (sachip->irq != NO_IRQ) {
ret = sa1111_setup_irq(sachip, pd->irq_base);
if (ret)
goto err_unmap;
}
#ifdef CONFIG_ARCH_SA1100
{
unsigned int val;
......@@ -789,24 +790,14 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
}
#endif
/*
* The interrupt controller must be initialised before any
* other device to ensure that the interrupts are available.
*/
if (sachip->irq != NO_IRQ)
sa1111_setup_irq(sachip);
g_sa1111 = sachip;
has_devs = ~0;
if (machine_is_assabet() || machine_is_jornada720() ||
machine_is_badge4())
has_devs &= ~(1 << 4);
else
has_devs &= ~(1 << 1);
if (pd)
has_devs &= ~pd->disable_devs;
for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++)
if (has_devs & (1 << i))
if (sa1111_devices[i].devid & has_devs)
sa1111_init_one_child(sachip, mem, &sa1111_devices[i]);
return 0;
......@@ -824,7 +815,10 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
static int sa1111_remove_one(struct device *dev, void *data)
{
device_unregister(dev);
struct sa1111_dev *sadev = SA1111_DEV(dev);
device_del(&sadev->dev);
release_resource(&sadev->res);
put_device(&sadev->dev);
return 0;
}
......@@ -846,6 +840,7 @@ static void __sa1111_remove(struct sa1111 *sachip)
if (sachip->irq != NO_IRQ) {
irq_set_chained_handler(sachip->irq, NULL);
irq_set_handler_data(sachip->irq, NULL);
irq_free_descs(sachip->irq_base, SA1111_IRQ_NR);
release_mem_region(sachip->phys + SA1111_INTC, 512);
}
......@@ -904,6 +899,9 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0);
save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1);
sa1111_writel(0, sachip->base + SA1111_SKPWM0);
sa1111_writel(0, sachip->base + SA1111_SKPWM1);
base = sachip->base + SA1111_INTC;
save->intpol0 = sa1111_readl(base + SA1111_INTPOL0);
save->intpol1 = sa1111_readl(base + SA1111_INTPOL1);
......@@ -919,13 +917,15 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
*/
val = sa1111_readl(sachip->base + SA1111_SKCR);
sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR);
sa1111_writel(0, sachip->base + SA1111_SKPWM0);
sa1111_writel(0, sachip->base + SA1111_SKPWM1);
clk_disable(sachip->clk);
spin_unlock_irqrestore(&sachip->lock, flags);
#ifdef CONFIG_ARCH_SA1100
sa1110_mb_disable();
#endif
return 0;
}
......@@ -966,6 +966,11 @@ static int sa1111_resume(struct platform_device *dev)
*/
sa1111_wake(sachip);
#ifdef CONFIG_ARCH_SA1100
/* Enable the memory bus request/grant signals */
sa1110_mb_enable();
#endif
/*
* Only lock for write ops. Also, sa1111_wake must be called with
* released spinlock!
......@@ -1053,6 +1058,7 @@ static struct platform_driver sa1111_device_driver = {
.resume = sa1111_resume,
.driver = {
.name = "sa1111",
.owner = THIS_MODULE,
},
};
......@@ -1238,16 +1244,23 @@ EXPORT_SYMBOL(sa1111_set_sleep_io);
* sa1111_enable_device - enable an on-chip SA1111 function block
* @sadev: SA1111 function block device to enable
*/
void sa1111_enable_device(struct sa1111_dev *sadev)
int sa1111_enable_device(struct sa1111_dev *sadev)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
unsigned long flags;
unsigned int val;
int ret = 0;
if (sachip->pdata && sachip->pdata->enable)
ret = sachip->pdata->enable(sachip->pdata->data, sadev->devid);
if (ret == 0) {
spin_lock_irqsave(&sachip->lock, flags);
val = sa1111_readl(sachip->base + SA1111_SKPCR);
sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
spin_unlock_irqrestore(&sachip->lock, flags);
}
return ret;
}
EXPORT_SYMBOL(sa1111_enable_device);
......@@ -1265,6 +1278,9 @@ void sa1111_disable_device(struct sa1111_dev *sadev)
val = sa1111_readl(sachip->base + SA1111_SKPCR);
sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
spin_unlock_irqrestore(&sachip->lock, flags);
if (sachip->pdata && sachip->pdata->disable)
sachip->pdata->disable(sachip->pdata->data, sadev->devid);
}
EXPORT_SYMBOL(sa1111_disable_device);
......@@ -1279,7 +1295,7 @@ static int sa1111_match(struct device *_dev, struct device_driver *_drv)
struct sa1111_dev *dev = SA1111_DEV(_dev);
struct sa1111_driver *drv = SA1111_DRV(_drv);
return dev->devid == drv->devid;
return dev->devid & drv->devid;
}
static int sa1111_bus_suspend(struct device *dev, pm_message_t state)
......@@ -1304,6 +1320,14 @@ static int sa1111_bus_resume(struct device *dev)
return ret;
}
static void sa1111_bus_shutdown(struct device *dev)
{
struct sa1111_driver *drv = SA1111_DRV(dev->driver);
if (drv && drv->shutdown)
drv->shutdown(SA1111_DEV(dev));
}
static int sa1111_bus_probe(struct device *dev)
{
struct sa1111_dev *sadev = SA1111_DEV(dev);
......@@ -1333,6 +1357,7 @@ struct bus_type sa1111_bus_type = {
.remove = sa1111_bus_remove,
.suspend = sa1111_bus_suspend,
.resume = sa1111_bus_resume,
.shutdown = sa1111_bus_shutdown,
};
EXPORT_SYMBOL(sa1111_bus_type);
......@@ -1349,9 +1374,70 @@ void sa1111_driver_unregister(struct sa1111_driver *driver)
}
EXPORT_SYMBOL(sa1111_driver_unregister);
#ifdef CONFIG_DMABOUNCE
/*
* According to the "Intel StrongARM SA-1111 Microprocessor Companion
* Chip Specification Update" (June 2000), erratum #7, there is a
* significant bug in the SA1111 SDRAM shared memory controller. If
* an access to a region of memory above 1MB relative to the bank base,
* it is important that address bit 10 _NOT_ be asserted. Depending
* on the configuration of the RAM, bit 10 may correspond to one
* of several different (processor-relative) address bits.
*
* This routine only identifies whether or not a given DMA address
* is susceptible to the bug.
*
* This should only get called for sa1111_device types due to the
* way we configure our device dma_masks.
*/
static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
{
/*
* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
* User's Guide" mentions that jumpers R51 and R52 control the
* target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
* SDRAM bank 1 on Neponset). The default configuration selects
* Assabet, so any address in bank 1 is necessarily invalid.
*/
return (machine_is_assabet() || machine_is_pfs168()) &&
(addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
}
static int sa1111_notifier_call(struct notifier_block *n, unsigned long action,
void *data)
{
struct sa1111_dev *dev = SA1111_DEV(data);
switch (action) {
case BUS_NOTIFY_ADD_DEVICE:
if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL) {
int ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
sa1111_needs_bounce);
if (ret)
dev_err(&dev->dev, "failed to register with dmabounce: %d\n", ret);
}
break;
case BUS_NOTIFY_DEL_DEVICE:
if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL)
dmabounce_unregister_dev(&dev->dev);
break;
}
return NOTIFY_OK;
}
static struct notifier_block sa1111_bus_notifier = {
.notifier_call = sa1111_notifier_call,
};
#endif
static int __init sa1111_init(void)
{
int ret = bus_register(&sa1111_bus_type);
#ifdef CONFIG_DMABOUNCE
if (ret == 0)
bus_register_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
#endif
if (ret == 0)
platform_driver_register(&sa1111_device_driver);
return ret;
......@@ -1360,6 +1446,9 @@ static int __init sa1111_init(void)
static void __exit sa1111_exit(void)
{
platform_driver_unregister(&sa1111_device_driver);
#ifdef CONFIG_DMABOUNCE
bus_unregister_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
#endif
bus_unregister(&sa1111_bus_type);
}
......
......@@ -132,33 +132,9 @@
#define SKPCR_DCLKEN (1<<7)
#define SKPCR_PWMCLKEN (1<<8)
/*
* USB Host controller
*/
/* USB Host controller */
#define SA1111_USB 0x0400
/*
* Offsets from SA1111_USB_BASE
*/
#define SA1111_USB_STATUS 0x0118
#define SA1111_USB_RESET 0x011c
#define SA1111_USB_IRQTEST 0x0120
#define USB_RESET_FORCEIFRESET (1 << 0)
#define USB_RESET_FORCEHCRESET (1 << 1)
#define USB_RESET_CLKGENRESET (1 << 2)
#define USB_RESET_SIMSCALEDOWN (1 << 3)
#define USB_RESET_USBINTTEST (1 << 4)
#define USB_RESET_SLEEPSTBYEN (1 << 5)
#define USB_RESET_PWRSENSELOW (1 << 6)
#define USB_RESET_PWRCTRLLOW (1 << 7)
#define USB_STATUS_IRQHCIRMTWKUP (1 << 7)
#define USB_STATUS_IRQHCIBUFFACC (1 << 8)
#define USB_STATUS_NIRQHCIM (1 << 9)
#define USB_STATUS_NHCIMFCLR (1 << 10)
#define USB_STATUS_USBPWRSENSE (1 << 11)
/*
* Serial Audio Controller
*
......@@ -327,22 +303,6 @@
* PC_SSR GPIO Block C Sleep State
*/
#define _PA_DDR _SA1111( 0x1000 )
#define _PA_DRR _SA1111( 0x1004 )
#define _PA_DWR _SA1111( 0x1004 )
#define _PA_SDR _SA1111( 0x1008 )
#define _PA_SSR _SA1111( 0x100c )
#define _PB_DDR _SA1111( 0x1010 )
#define _PB_DRR _SA1111( 0x1014 )
#define _PB_DWR _SA1111( 0x1014 )
#define _PB_SDR _SA1111( 0x1018 )
#define _PB_SSR _SA1111( 0x101c )
#define _PC_DDR _SA1111( 0x1020 )
#define _PC_DRR _SA1111( 0x1024 )
#define _PC_DWR _SA1111( 0x1024 )
#define _PC_SDR _SA1111( 0x1028 )
#define _PC_SSR _SA1111( 0x102c )
#define SA1111_GPIO 0x1000
#define SA1111_GPIO_PADDR (0x000)
......@@ -425,106 +385,30 @@
#define SA1111_WAKEPOL0 0x0034
#define SA1111_WAKEPOL1 0x0038
/*
* PS/2 Trackpad and Mouse Interfaces
*
* Registers
* PS2CR Control Register
* PS2STAT Status Register
* PS2DATA Transmit/Receive Data register
* PS2CLKDIV Clock Division Register
* PS2PRECNT Clock Precount Register
* PS2TEST1 Test register 1
* PS2TEST2 Test register 2
* PS2TEST3 Test register 3
* PS2TEST4 Test register 4
*/
/* PS/2 Trackpad and Mouse Interfaces */
#define SA1111_KBD 0x0a00
#define SA1111_MSE 0x0c00
/*
* These are offsets from the above bases.
*/
#define SA1111_PS2CR 0x0000
#define SA1111_PS2STAT 0x0004
#define SA1111_PS2DATA 0x0008
#define SA1111_PS2CLKDIV 0x000c
#define SA1111_PS2PRECNT 0x0010
#define PS2CR_ENA 0x08
#define PS2CR_FKD 0x02
#define PS2CR_FKC 0x01
#define PS2STAT_STP 0x0100
#define PS2STAT_TXE 0x0080
#define PS2STAT_TXB 0x0040
#define PS2STAT_RXF 0x0020
#define PS2STAT_RXB 0x0010
#define PS2STAT_ENA 0x0008
#define PS2STAT_RXP 0x0004
#define PS2STAT_KBD 0x0002
#define PS2STAT_KBC 0x0001
/*
* PCMCIA Interface
*
* Registers
* PCSR Status Register
* PCCR Control Register
* PCSSR Sleep State Register
*/
/* PCMCIA Interface */
#define SA1111_PCMCIA 0x1600
/*
* These are offsets from the above base.
*/
#define SA1111_PCCR 0x0000
#define SA1111_PCSSR 0x0004
#define SA1111_PCSR 0x0008
#define PCSR_S0_READY (1<<0)
#define PCSR_S1_READY (1<<1)
#define PCSR_S0_DETECT (1<<2)
#define PCSR_S1_DETECT (1<<3)
#define PCSR_S0_VS1 (1<<4)
#define PCSR_S0_VS2 (1<<5)
#define PCSR_S1_VS1 (1<<6)
#define PCSR_S1_VS2 (1<<7)
#define PCSR_S0_WP (1<<8)
#define PCSR_S1_WP (1<<9)
#define PCSR_S0_BVD1 (1<<10)
#define PCSR_S0_BVD2 (1<<11)
#define PCSR_S1_BVD1 (1<<12)
#define PCSR_S1_BVD2 (1<<13)
#define PCCR_S0_RST (1<<0)
#define PCCR_S1_RST (1<<1)
#define PCCR_S0_FLT (1<<2)
#define PCCR_S1_FLT (1<<3)
#define PCCR_S0_PWAITEN (1<<4)
#define PCCR_S1_PWAITEN (1<<5)
#define PCCR_S0_PSE (1<<6)
#define PCCR_S1_PSE (1<<7)
#define PCSSR_S0_SLEEP (1<<0)
#define PCSSR_S1_SLEEP (1<<1)
extern struct bus_type sa1111_bus_type;
#define SA1111_DEVID_SBI 0
#define SA1111_DEVID_SK 1
#define SA1111_DEVID_USB 2
#define SA1111_DEVID_SAC 3
#define SA1111_DEVID_SSP 4
#define SA1111_DEVID_PS2 5
#define SA1111_DEVID_GPIO 6
#define SA1111_DEVID_INT 7
#define SA1111_DEVID_PCMCIA 8
#define SA1111_DEVID_SBI (1 << 0)
#define SA1111_DEVID_SK (1 << 1)
#define SA1111_DEVID_USB (1 << 2)
#define SA1111_DEVID_SAC (1 << 3)
#define SA1111_DEVID_SSP (1 << 4)
#define SA1111_DEVID_PS2 (3 << 5)
#define SA1111_DEVID_PS2_KBD (1 << 5)
#define SA1111_DEVID_PS2_MSE (1 << 6)
#define SA1111_DEVID_GPIO (1 << 7)
#define SA1111_DEVID_INT (1 << 8)
#define SA1111_DEVID_PCMCIA (1 << 9)
struct sa1111_dev {
struct device dev;
......@@ -548,6 +432,7 @@ struct sa1111_driver {
int (*remove)(struct sa1111_dev *);
int (*suspend)(struct sa1111_dev *, pm_message_t);
int (*resume)(struct sa1111_dev *);
void (*shutdown)(struct sa1111_dev *);
};
#define SA1111_DRV(_d) container_of((_d), struct sa1111_driver, drv)
......@@ -555,9 +440,10 @@ struct sa1111_driver {
#define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name)
/*
* These frob the SKPCR register.
* These frob the SKPCR register, and call platform specific
* enable/disable functions.
*/
void sa1111_enable_device(struct sa1111_dev *);
int sa1111_enable_device(struct sa1111_dev *);
void sa1111_disable_device(struct sa1111_dev *);
unsigned int sa1111_pll_clock(struct sa1111_dev *);
......@@ -580,6 +466,10 @@ void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned i
struct sa1111_platform_data {
int irq_base; /* base for cascaded on-chip IRQs */
unsigned disable_devs;
void *data;
int (*enable)(void *, unsigned);
void (*disable)(void *, unsigned);
};
#endif /* _ASM_ARCH_SA1111 */
......@@ -30,10 +30,7 @@
#include <asm/mach/time.h>
#define IRQ_MASK 0xfe000000 /* read */
#define IRQ_MSET 0xfe000000 /* write */
#define IRQ_STAT 0xff000000 /* read */
#define IRQ_MCLR 0xff000000 /* write */
#include "core.h"
static void ebsa110_mask_irq(struct irq_data *d)
{
......@@ -79,22 +76,22 @@ static struct map_desc ebsa110_io_desc[] __initdata = {
{ /* IRQ_STAT/IRQ_MCLR */
.virtual = IRQ_STAT,
.pfn = __phys_to_pfn(TRICK4_PHYS),
.length = PGDIR_SIZE,
.length = TRICK4_SIZE,
.type = MT_DEVICE
}, { /* IRQ_MASK/IRQ_MSET */
.virtual = IRQ_MASK,
.pfn = __phys_to_pfn(TRICK3_PHYS),
.length = PGDIR_SIZE,
.length = TRICK3_SIZE,
.type = MT_DEVICE
}, { /* SOFT_BASE */
.virtual = SOFT_BASE,
.pfn = __phys_to_pfn(TRICK1_PHYS),
.length = PGDIR_SIZE,
.length = TRICK1_SIZE,
.type = MT_DEVICE
}, { /* PIT_BASE */
.virtual = PIT_BASE,
.pfn = __phys_to_pfn(TRICK0_PHYS),
.length = PGDIR_SIZE,
.length = TRICK0_SIZE,
.type = MT_DEVICE
},
......
/*
* Copyright (C) 1996-2000 Russell King.
*
* 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.
*
* This file contains the core hardware definitions of the EBSA-110.
*/
#ifndef CORE_H
#define CORE_H
/* Physical addresses/sizes */
#define ISAMEM_PHYS 0xe0000000
#define ISAMEM_SIZE 0x10000000
#define ISAIO_PHYS 0xf0000000
#define ISAIO_SIZE PGDIR_SIZE
#define TRICK0_PHYS 0xf2000000
#define TRICK0_SIZE PGDIR_SIZE
#define TRICK1_PHYS 0xf2400000
#define TRICK1_SIZE PGDIR_SIZE
#define TRICK2_PHYS 0xf2800000
#define TRICK3_PHYS 0xf2c00000
#define TRICK3_SIZE PGDIR_SIZE
#define TRICK4_PHYS 0xf3000000
#define TRICK4_SIZE PGDIR_SIZE
#define TRICK5_PHYS 0xf3400000
#define TRICK6_PHYS 0xf3800000
#define TRICK7_PHYS 0xf3c00000
/* Virtual addresses */
#define PIT_BASE 0xfc000000 /* trick 0 */
#define SOFT_BASE 0xfd000000 /* trick 1 */
#define IRQ_MASK 0xfe000000 /* trick 3 - read */
#define IRQ_MSET 0xfe000000 /* trick 3 - write */
#define IRQ_STAT 0xff000000 /* trick 4 - read */
#define IRQ_MCLR 0xff000000 /* trick 4 - write */
#endif
......@@ -12,48 +12,9 @@
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
/*
* The EBSA110 has a weird "ISA IO" region:
*
* Region 0 (addr = 0xf0000000 + io << 2)
* --------------------------------------------------------
* Physical region IO region
* f0000fe0 - f0000ffc 3f8 - 3ff ttyS0
* f0000e60 - f0000e64 398 - 399
* f0000de0 - f0000dfc 378 - 37f lp0
* f0000be0 - f0000bfc 2f8 - 2ff ttyS1
*
* Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
* --------------------------------------------------------
* Physical region IO region
* f00014f1 a79 pnp write data
* f00007c0 - f00007c1 3e0 - 3e1 pcmcia
* f00004f1 279 pnp address
* f0000440 - f000046c 220 - 236 eth0
* f0000405 203 pnp read data
*/
#define ISAMEM_PHYS 0xe0000000
#define ISAMEM_SIZE 0x10000000
#define ISAIO_PHYS 0xf0000000
#define ISAIO_SIZE PGDIR_SIZE
#define TRICK0_PHYS 0xf2000000
#define TRICK1_PHYS 0xf2400000
#define TRICK2_PHYS 0xf2800000
#define TRICK3_PHYS 0xf2c00000
#define TRICK4_PHYS 0xf3000000
#define TRICK5_PHYS 0xf3400000
#define TRICK6_PHYS 0xf3800000
#define TRICK7_PHYS 0xf3c00000
#define ISAMEM_BASE 0xe0000000
#define ISAIO_BASE 0xf0000000
#define PIT_BASE 0xfc000000
#define SOFT_BASE 0xfd000000
/*
* RAM definitions
*/
......
......@@ -177,6 +177,26 @@ void writesl(void __iomem *addr, const void *data, int len)
}
EXPORT_SYMBOL(writesl);
/*
* The EBSA110 has a weird "ISA IO" region:
*
* Region 0 (addr = 0xf0000000 + io << 2)
* --------------------------------------------------------
* Physical region IO region
* f0000fe0 - f0000ffc 3f8 - 3ff ttyS0
* f0000e60 - f0000e64 398 - 399
* f0000de0 - f0000dfc 378 - 37f lp0
* f0000be0 - f0000bfc 2f8 - 2ff ttyS1
*
* Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
* --------------------------------------------------------
* Physical region IO region
* f00014f1 a79 pnp write data
* f00007c0 - f00007c1 3e0 - 3e1 pcmcia
* f00004f1 279 pnp address
* f0000440 - f000046c 220 - 236 eth0
* f0000405 203 pnp read data
*/
#define SUPERIO_PORT(p) \
(((p) >> 3) == (0x3f8 >> 3) || \
((p) >> 3) == (0x2f8 >> 3) || \
......
......@@ -20,6 +20,8 @@
#include <asm/system.h>
#include <asm/mach-types.h>
#include "core.h"
static spinlock_t leds_lock;
static void ebsa110_leds_event(led_event_t ledevt)
......
......@@ -223,6 +223,7 @@ static struct resource sa1111_resources[] = {
static struct sa1111_platform_data sa1111_info = {
.irq_base = LUBBOCK_SA1111_IRQ_BASE,
.disable_devs = SA1111_DEVID_SAC,
};
static struct platform_device sa1111_device = {
......
......@@ -3,7 +3,7 @@
#
# Common support
obj-y := clock.o generic.o irq.o dma.o time.o #nmi-oopser.o
obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o
obj-m :=
obj-n :=
obj- :=
......
......@@ -15,14 +15,16 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/serial_core.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <video/sa1100fb.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/irq.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/pgtable-hwdef.h>
......@@ -36,17 +38,18 @@
#include <asm/mach/serial_sa1100.h>
#include <mach/assabet.h>
#include <mach/mcp.h>
#include <mach/irqs.h>
#include "generic.h"
#define ASSABET_BCR_DB1110 \
(ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \
(ASSABET_BCR_SPK_OFF | \
ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \
ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \
ASSABET_BCR_IRDA_MD0)
#define ASSABET_BCR_DB1111 \
(ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \
(ASSABET_BCR_SPK_OFF | \
ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \
ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \
ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
......@@ -69,31 +72,10 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
EXPORT_SYMBOL(ASSABET_BCR_frob);
static void assabet_backlight_power(int on)
static void assabet_ucb1x00_reset(enum ucb1x00_reset state)
{
#ifndef ASSABET_PAL_VIDEO
if (on)
ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
else
#endif
ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
}
/*
* Turn on/off the backlight. When turning the backlight on,
* we wait 500us after turning it on so we don't cause the
* supplies to droop when we enable the LCD controller (and
* cause a hard reset.)
*/
static void assabet_lcd_power(int on)
{
#ifndef ASSABET_PAL_VIDEO
if (on) {
ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
udelay(500);
} else
#endif
ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
if (state == UCB_RST_PROBE)
ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
}
......@@ -152,15 +134,8 @@ static struct flash_platform_data assabet_flash_data = {
};
static struct resource assabet_flash_resources[] = {
{
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
}, {
.start = SA1100_CS1_PHYS,
.end = SA1100_CS1_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
}
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M),
};
......@@ -199,18 +174,126 @@ static struct irda_platform_data assabet_irda_data = {
.set_speed = assabet_irda_set_speed,
};
static struct ucb1x00_plat_data assabet_ucb1x00_data = {
.reset = assabet_ucb1x00_reset,
.gpio_base = -1,
};
static struct mcp_plat_data assabet_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.codec_pdata = &assabet_ucb1x00_data,
};
static void assabet_lcd_set_visual(u32 visual)
{
u_int is_true_color = visual == FB_VISUAL_TRUECOLOR;
if (machine_is_assabet()) {
#if 1 // phase 4 or newer Assabet's
if (is_true_color)
ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
else
ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
#else
// older Assabet's
if (is_true_color)
ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
else
ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
#endif
}
}
#ifndef ASSABET_PAL_VIDEO
static void assabet_lcd_backlight_power(int on)
{
if (on)
ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
else
ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
}
/*
* Turn on/off the backlight. When turning the backlight on, we wait
* 500us after turning it on so we don't cause the supplies to droop
* when we enable the LCD controller (and cause a hard reset.)
*/
static void assabet_lcd_power(int on)
{
if (on) {
ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
udelay(500);
} else
ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
}
/*
* The assabet uses a sharp LQ039Q2DS54 LCD module. It is actually
* takes an RGB666 signal, but we provide it with an RGB565 signal
* instead (def_rgb_16).
*/
static struct sa1100fb_mach_info lq039q2ds54_info = {
.pixclock = 171521, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 5, .vsync_len = 1,
.left_margin = 61, .upper_margin = 3,
.right_margin = 9, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
.backlight_power = assabet_lcd_backlight_power,
.lcd_power = assabet_lcd_power,
.set_visual = assabet_lcd_set_visual,
};
#else
static void assabet_pal_backlight_power(int on)
{
ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
}
static void assabet_pal_power(int on)
{
ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
}
static struct sa1100fb_mach_info pal_info = {
.pixclock = 67797, .bpp = 16,
.xres = 640, .yres = 512,
.hsync_len = 64, .vsync_len = 6,
.left_margin = 125, .upper_margin = 70,
.right_margin = 115, .lower_margin = 36,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
.backlight_power = assabet_pal_backlight_power,
.lcd_power = assabet_pal_power,
.set_visual = assabet_lcd_set_visual,
};
#endif
#ifdef CONFIG_ASSABET_NEPONSET
static struct resource neponset_resources[] = {
DEFINE_RES_MEM(0x10000000, 0x08000000),
DEFINE_RES_MEM(0x18000000, 0x04000000),
DEFINE_RES_MEM(0x40000000, SZ_8K),
DEFINE_RES_IRQ(IRQ_GPIO25),
};
#endif
static void __init assabet_init(void)
{
/*
* Ensure that the power supply is in "high power" mode.
*/
GPDR |= GPIO_GPIO16;
GPSR = GPIO_GPIO16;
GPDR |= GPIO_GPIO16;
/*
* Ensure that these pins are set as outputs and are driving
......@@ -218,8 +301,16 @@ static void __init assabet_init(void)
* the WS latch in the CPLD, and we don't float causing
* excessive power drain. --rmk
*/
GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
/*
* Also set GPIO27 as an output; this is used to clock UART3
* via the FPGA and as otherwise has no pullups or pulldowns,
* so stop it floating.
*/
GPCR = GPIO_GPIO27;
GPDR |= GPIO_GPIO27;
/*
* Set up registers for sleep mode.
......@@ -231,8 +322,7 @@ static void __init assabet_init(void)
PPDR |= PPC_TXD3 | PPC_TXD1;
PPSR |= PPC_TXD3 | PPC_TXD1;
sa1100fb_lcd_power = assabet_lcd_power;
sa1100fb_backlight_power = assabet_backlight_power;
sa11x0_ppc_configure_mcp();
if (machine_has_neponset()) {
/*
......@@ -246,9 +336,17 @@ static void __init assabet_init(void)
#ifndef CONFIG_ASSABET_NEPONSET
printk( "Warning: Neponset detected but full support "
"hasn't been configured in the kernel\n" );
#else
platform_device_register_simple("neponset", 0,
neponset_resources, ARRAY_SIZE(neponset_resources));
#endif
}
#ifndef ASSABET_PAL_VIDEO
sa11x0_register_lcd(&lq039q2ds54_info);
#else
sa11x0_register_lcd(&pal_video);
#endif
sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
ARRAY_SIZE(assabet_flash_resources));
sa11x0_register_irda(&assabet_irda_data);
......@@ -412,21 +510,8 @@ static void __init assabet_map_io(void)
*/
Ser1SDCR0 |= SDCR0_SUS;
if (machine_has_neponset()) {
#ifdef CONFIG_ASSABET_NEPONSET
extern void neponset_map_io(void);
/*
* We map Neponset registers even if it isn't present since
* many drivers will try to probe their stuff (and fail).
* This is still more friendly than a kernel paging request
* crash.
*/
neponset_map_io();
#endif
} else {
if (!machine_has_neponset())
sa1100_register_uart_fns(&assabet_port_fns);
}
/*
* When Neponset is attached, the first UART should be
......@@ -449,6 +534,7 @@ MACHINE_START(ASSABET, "Intel-Assabet")
.atag_offset = 0x100,
.fixup = fixup_assabet,
.map_io = assabet_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = assabet_init,
......
......@@ -39,20 +39,27 @@
#include "generic.h"
static struct resource sa1111_resources[] = {
[0] = {
.start = BADGE4_SA1111_BASE,
.end = BADGE4_SA1111_BASE + 0x00001fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = BADGE4_IRQ_GPIO_SA1111,
.end = BADGE4_IRQ_GPIO_SA1111,
.flags = IORESOURCE_IRQ,
},
[0] = DEFINE_RES_MEM(BADGE4_SA1111_BASE, 0x2000),
[1] = DEFINE_RES_IRQ(BADGE4_IRQ_GPIO_SA1111),
};
static int badge4_sa1111_enable(void *data, unsigned devid)
{
if (devid == SA1111_DEVID_USB)
badge4_set_5V(BADGE4_5V_USB, 1);
return 0;
}
static void badge4_sa1111_disable(void *data, unsigned devid)
{
if (devid == SA1111_DEVID_USB)
badge4_set_5V(BADGE4_5V_USB, 0);
}
static struct sa1111_platform_data sa1111_info = {
.irq_base = IRQ_BOARD_END,
.disable_devs = SA1111_DEVID_PS2_MSE,
.enable = badge4_sa1111_enable,
.disable = badge4_sa1111_disable,
};
static u64 sa1111_dmamask = 0xffffffffUL;
......@@ -121,11 +128,8 @@ static struct flash_platform_data badge4_flash_data = {
.nr_parts = ARRAY_SIZE(badge4_partitions),
};
static struct resource badge4_flash_resource = {
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_64M - 1,
.flags = IORESOURCE_MEM,
};
static struct resource badge4_flash_resource =
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_64M);
static int five_v_on __initdata = 0;
......@@ -269,11 +273,6 @@ static struct map_desc badge4_io_desc[] __initdata = {
.pfn = __phys_to_pfn(0x10000000),
.length = 0x00100000,
.type = MT_DEVICE
}, { /* SA-1111 */
.virtual = 0xf4000000,
.pfn = __phys_to_pfn(0x48000000),
.length = 0x00100000,
.type = MT_DEVICE
}
};
......@@ -304,6 +303,7 @@ static void __init badge4_map_io(void)
MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
.atag_offset = 0x100,
.map_io = badge4_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
#ifdef CONFIG_SA1111
......
......@@ -18,7 +18,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <asm/setup.h>
......@@ -30,14 +29,11 @@
#include <mach/cerf.h>
#include <mach/mcp.h>
#include <mach/irqs.h>
#include "generic.h"
static struct resource cerfuart2_resources[] = {
[0] = {
.start = 0x80030000,
.end = 0x8003ffff,
.flags = IORESOURCE_MEM,
},
[0] = DEFINE_RES_MEM(0x80030000, SZ_64K),
};
static struct platform_device cerfuart2_device = {
......@@ -87,11 +83,8 @@ static struct flash_platform_data cerf_flash_data = {
.nr_parts = ARRAY_SIZE(cerf_partitions),
};
static struct resource cerf_flash_resource = {
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
};
static struct resource cerf_flash_resource =
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
static void __init cerf_init_irq(void)
{
......@@ -128,6 +121,7 @@ static struct mcp_plat_data cerf_mcp_data = {
static void __init cerf_init(void)
{
sa11x0_ppc_configure_mcp();
platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
sa11x0_register_mcp(&cerf_mcp_data);
......@@ -136,6 +130,7 @@ static void __init cerf_init(void)
MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
/* Maintainer: support@intrinsyc.com */
.map_io = cerf_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = cerf_init_irq,
.timer = &sa1100_timer,
.init_machine = cerf_init,
......
......@@ -22,15 +22,17 @@
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/pda_power.h>
#include <video/sa1100fb.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/setup.h>
#include <mach/collie.h>
......@@ -44,15 +46,12 @@
#include <asm/mach/sharpsl_param.h>
#include <asm/hardware/locomo.h>
#include <mach/mcp.h>
#include <mach/irqs.h>
#include "generic.h"
static struct resource collie_scoop_resources[] = {
[0] = {
.start = 0x40800000,
.end = 0x40800fff,
.flags = IORESOURCE_MEM,
},
[0] = DEFINE_RES_MEM(0x40800000, SZ_4K),
};
static struct scoop_config collie_scoop_setup = {
......@@ -85,10 +84,14 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
.num_devs = 1,
};
static struct ucb1x00_plat_data collie_ucb1x00_data = {
.gpio_base = COLLIE_TC35143_GPIO_BASE,
};
static struct mcp_plat_data collie_mcp_data = {
.mccr0 = MCCR0_ADM | MCCR0_ExtClk,
.sclk_rate = 9216000,
.gpio_base = COLLIE_TC35143_GPIO_BASE,
.codec_pdata = &collie_ucb1x00_data,
};
/*
......@@ -221,16 +224,8 @@ device_initcall(collie_uart_init);
static struct resource locomo_resources[] = {
[0] = {
.start = 0x40000000,
.end = 0x40001fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_GPIO25,
.end = IRQ_GPIO25,
.flags = IORESOURCE_IRQ,
},
[0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
[1] = DEFINE_RES_IRQ(IRQ_GPIO25),
};
static struct locomo_platform_data locomo_info = {
......@@ -303,11 +298,21 @@ static struct flash_platform_data collie_flash_data = {
};
static struct resource collie_flash_resources[] = {
{
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
}
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
};
static struct sa1100fb_mach_info collie_lcd_info = {
.pixclock = 171521, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 5, .vsync_len = 1,
.left_margin = 11, .upper_margin = 2,
.right_margin = 30, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
};
static void __init collie_init(void)
......@@ -341,6 +346,10 @@ static void __init collie_init(void)
collie_power_resource[0].start = gpio_to_irq(COLLIE_GPIO_AC_IN);
collie_power_resource[0].end = gpio_to_irq(COLLIE_GPIO_AC_IN);
sa11x0_ppc_configure_mcp();
platform_scoop_config = &collie_pcmcia_config;
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
......@@ -348,6 +357,7 @@ static void __init collie_init(void)
printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
}
sa11x0_register_lcd(&collie_lcd_info);
sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
ARRAY_SIZE(collie_flash_resources));
sa11x0_register_mcp(&collie_mcp_data);
......@@ -383,6 +393,7 @@ static void __init collie_map_io(void)
MACHINE_START(COLLIE, "Sharp-Collie")
.map_io = collie_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = collie_init,
......
/*
* arch/arm/mach-sa1100/dma.c
*
* Support functions for the SA11x0 internal DMA channels.
*
* Copyright (C) 2000, 2001 by Nicolas Pitre
*
* 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.
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/dma.h>
#undef DEBUG
#ifdef DEBUG
#define DPRINTK( s, arg... ) printk( "dma<%p>: " s, regs , ##arg )
#else
#define DPRINTK( x... )
#endif
typedef struct {
const char *device_id; /* device name */
u_long device; /* this channel device, 0 if unused*/
dma_callback_t callback; /* to call when DMA completes */
void *data; /* ... with private data ptr */
} sa1100_dma_t;
static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS];
static DEFINE_SPINLOCK(dma_list_lock);
static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
dma_regs_t *dma_regs = dev_id;
sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7);
int status = dma_regs->RdDCSR;
if (status & (DCSR_ERROR)) {
printk(KERN_CRIT "DMA on \"%s\" caused an error\n", dma->device_id);
dma_regs->ClrDCSR = DCSR_ERROR;
}
dma_regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB);
if (dma->callback) {
if (status & DCSR_DONEA)
dma->callback(dma->data);
if (status & DCSR_DONEB)
dma->callback(dma->data);
}
return IRQ_HANDLED;
}
/**
* sa1100_request_dma - allocate one of the SA11x0's DMA channels
* @device: The SA11x0 peripheral targeted by this request
* @device_id: An ascii name for the claiming device
* @callback: Function to be called when the DMA completes
* @data: A cookie passed back to the callback function
* @dma_regs: Pointer to the location of the allocated channel's identifier
*
* This function will search for a free DMA channel and returns the
* address of the hardware registers for that channel as the channel
* identifier. This identifier is written to the location pointed by
* @dma_regs. The list of possible values for @device are listed into
* arch/arm/mach-sa1100/include/mach/dma.h as a dma_device_t enum.
*
* Note that reading from a port and writing to the same port are
* actually considered as two different streams requiring separate
* DMA registrations.
*
* The @callback function is called from interrupt context when one
* of the two possible DMA buffers in flight has terminated. That
* function has to be small and efficient while posponing more complex
* processing to a lower priority execution context.
*
* If no channels are available, or if the desired @device is already in
* use by another DMA channel, then an error code is returned. This
* function must be called before any other DMA calls.
**/
int sa1100_request_dma (dma_device_t device, const char *device_id,
dma_callback_t callback, void *data,
dma_regs_t **dma_regs)
{
sa1100_dma_t *dma = NULL;
dma_regs_t *regs;
int i, err;
*dma_regs = NULL;
err = 0;
spin_lock(&dma_list_lock);
for (i = 0; i < SA1100_DMA_CHANNELS; i++) {
if (dma_chan[i].device == device) {
err = -EBUSY;
break;
} else if (!dma_chan[i].device && !dma) {
dma = &dma_chan[i];
}
}
if (!err) {
if (dma)
dma->device = device;
else
err = -ENOSR;
}
spin_unlock(&dma_list_lock);
if (err)
return err;
i = dma - dma_chan;
regs = (dma_regs_t *)&DDAR(i);
err = request_irq(IRQ_DMA0 + i, dma_irq_handler, IRQF_DISABLED,
device_id, regs);
if (err) {
printk(KERN_ERR
"%s: unable to request IRQ %d for %s\n",
__func__, IRQ_DMA0 + i, device_id);
dma->device = 0;
return err;
}
*dma_regs = regs;
dma->device_id = device_id;
dma->callback = callback;
dma->data = data;
regs->ClrDCSR =
(DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
DCSR_IE | DCSR_ERROR | DCSR_RUN);
regs->DDAR = device;
return 0;
}
/**
* sa1100_free_dma - free a SA11x0 DMA channel
* @regs: identifier for the channel to free
*
* This clears all activities on a given DMA channel and releases it
* for future requests. The @regs identifier is provided by a
* successful call to sa1100_request_dma().
**/
void sa1100_free_dma(dma_regs_t *regs)
{
int i;
for (i = 0; i < SA1100_DMA_CHANNELS; i++)
if (regs == (dma_regs_t *)&DDAR(i))
break;
if (i >= SA1100_DMA_CHANNELS) {
printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
return;
}
if (!dma_chan[i].device) {
printk(KERN_ERR "%s: Trying to free free DMA\n", __func__);
return;
}
regs->ClrDCSR =
(DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
DCSR_IE | DCSR_ERROR | DCSR_RUN);
free_irq(IRQ_DMA0 + i, regs);
dma_chan[i].device = 0;
}
/**
* sa1100_start_dma - submit a data buffer for DMA
* @regs: identifier for the channel to use
* @dma_ptr: buffer physical (or bus) start address
* @size: buffer size
*
* This function hands the given data buffer to the hardware for DMA
* access. If another buffer is already in flight then this buffer
* will be queued so the DMA engine will switch to it automatically
* when the previous one is done. The DMA engine is actually toggling
* between two buffers so at most 2 successful calls can be made before
* one of them terminates and the callback function is called.
*
* The @regs identifier is provided by a successful call to
* sa1100_request_dma().
*
* The @size must not be larger than %MAX_DMA_SIZE. If a given buffer
* is larger than that then it's the caller's responsibility to split
* it into smaller chunks and submit them separately. If this is the
* case then a @size of %CUT_DMA_SIZE is recommended to avoid ending
* up with too small chunks. The callback function can be used to chain
* submissions of buffer chunks.
*
* Error return values:
* %-EOVERFLOW: Given buffer size is too big.
* %-EBUSY: Both DMA buffers are already in use.
* %-EAGAIN: Both buffers were busy but one of them just completed
* but the interrupt handler has to execute first.
*
* This function returs 0 on success.
**/
int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size)
{
unsigned long flags;
u_long status;
int ret;
if (dma_ptr & 3)
printk(KERN_WARNING "DMA: unaligned start address (0x%08lx)\n",
(unsigned long)dma_ptr);
if (size > MAX_DMA_SIZE)
return -EOVERFLOW;
local_irq_save(flags);
status = regs->RdDCSR;
/* If both DMA buffers are started, there's nothing else we can do. */
if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) {
DPRINTK("start: st %#x busy\n", status);
ret = -EBUSY;
goto out;
}
if (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
(!(status & DCSR_BIU) && !(status & DCSR_STRTA))) {
if (status & DCSR_DONEA) {
/* give a chance for the interrupt to be processed */
ret = -EAGAIN;
goto out;
}
regs->DBSA = dma_ptr;
regs->DBTA = size;
regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN;
DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size);
} else {
if (status & DCSR_DONEB) {
/* give a chance for the interrupt to be processed */
ret = -EAGAIN;
goto out;
}
regs->DBSB = dma_ptr;
regs->DBTB = size;
regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN;
DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size);
}
ret = 0;
out:
local_irq_restore(flags);
return ret;
}
/**
* sa1100_get_dma_pos - return current DMA position
* @regs: identifier for the channel to use
*
* This function returns the current physical (or bus) address for the
* given DMA channel. If the channel is running i.e. not in a stopped
* state then the caller must disable interrupts prior calling this
* function and process the returned value before re-enabling them to
* prevent races with the completion interrupt handler and the callback
* function. The validation of the returned value is the caller's
* responsibility as well -- the hardware seems to return out of range
* values when the DMA engine completes a buffer.
*
* The @regs identifier is provided by a successful call to
* sa1100_request_dma().
**/
dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs)
{
int status;
/*
* We must determine whether buffer A or B is active.
* Two possibilities: either we are in the middle of
* a buffer, or the DMA controller just switched to the
* next toggle but the interrupt hasn't been serviced yet.
* The former case is straight forward. In the later case,
* we'll do like if DMA is just at the end of the previous
* toggle since all registers haven't been reset yet.
* This goes around the edge case and since we're always
* a little behind anyways it shouldn't make a big difference.
* If DMA has been stopped prior calling this then the
* position is exact.
*/
status = regs->RdDCSR;
if ((!(status & DCSR_BIU) && (status & DCSR_STRTA)) ||
( (status & DCSR_BIU) && !(status & DCSR_STRTB)))
return regs->DBSA;
else
return regs->DBSB;
}
/**
* sa1100_reset_dma - reset a DMA channel
* @regs: identifier for the channel to use
*
* This function resets and reconfigure the given DMA channel. This is
* particularly useful after a sleep/wakeup event.
*
* The @regs identifier is provided by a successful call to
* sa1100_request_dma().
**/
void sa1100_reset_dma(dma_regs_t *regs)
{
int i;
for (i = 0; i < SA1100_DMA_CHANNELS; i++)
if (regs == (dma_regs_t *)&DDAR(i))
break;
if (i >= SA1100_DMA_CHANNELS) {
printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
return;
}
regs->ClrDCSR =
(DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
DCSR_IE | DCSR_ERROR | DCSR_RUN);
regs->DDAR = dma_chan[i].device;
}
EXPORT_SYMBOL(sa1100_request_dma);
EXPORT_SYMBOL(sa1100_free_dma);
EXPORT_SYMBOL(sa1100_start_dma);
EXPORT_SYMBOL(sa1100_get_dma_pos);
EXPORT_SYMBOL(sa1100_reset_dma);
......@@ -14,18 +14,23 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/pm.h>
#include <linux/cpufreq.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <video/sa1100fb.h>
#include <asm/div64.h>
#include <mach/hardware.h>
#include <asm/system.h>
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include "generic.h"
unsigned int reset_status;
......@@ -149,16 +154,8 @@ static void sa11x0_register_device(struct platform_device *dev, void *data)
static struct resource sa11x0udc_resources[] = {
[0] = {
.start = __PREG(Ser0UDCCR),
.end = __PREG(Ser0UDCCR) + 0xffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_Ser0UDC,
.end = IRQ_Ser0UDC,
.flags = IORESOURCE_IRQ,
},
[0] = DEFINE_RES_MEM(__PREG(Ser0UDCCR), SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_Ser0UDC),
};
static u64 sa11x0udc_dma_mask = 0xffffffffUL;
......@@ -175,16 +172,8 @@ static struct platform_device sa11x0udc_device = {
};
static struct resource sa11x0uart1_resources[] = {
[0] = {
.start = __PREG(Ser1UTCR0),
.end = __PREG(Ser1UTCR0) + 0xffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_Ser1UART,
.end = IRQ_Ser1UART,
.flags = IORESOURCE_IRQ,
},
[0] = DEFINE_RES_MEM(__PREG(Ser1UTCR0), SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_Ser1UART),
};
static struct platform_device sa11x0uart1_device = {
......@@ -195,16 +184,8 @@ static struct platform_device sa11x0uart1_device = {
};
static struct resource sa11x0uart3_resources[] = {
[0] = {
.start = __PREG(Ser3UTCR0),
.end = __PREG(Ser3UTCR0) + 0xffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_Ser3UART,
.end = IRQ_Ser3UART,
.flags = IORESOURCE_IRQ,
},
[0] = DEFINE_RES_MEM(__PREG(Ser3UTCR0), SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_Ser3UART),
};
static struct platform_device sa11x0uart3_device = {
......@@ -215,16 +196,9 @@ static struct platform_device sa11x0uart3_device = {
};
static struct resource sa11x0mcp_resources[] = {
[0] = {
.start = __PREG(Ser4MCCR0),
.end = __PREG(Ser4MCCR0) + 0xffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_Ser4MCP,
.end = IRQ_Ser4MCP,
.flags = IORESOURCE_IRQ,
},
[0] = DEFINE_RES_MEM(__PREG(Ser4MCCR0), SZ_64K),
[1] = DEFINE_RES_MEM(__PREG(Ser4MCCR1), 4),
[2] = DEFINE_RES_IRQ(IRQ_Ser4MCP),
};
static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
......@@ -240,22 +214,24 @@ static struct platform_device sa11x0mcp_device = {
.resource = sa11x0mcp_resources,
};
void __init sa11x0_ppc_configure_mcp(void)
{
/* Setup the PPC unit for the MCP */
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
}
void sa11x0_register_mcp(struct mcp_plat_data *data)
{
sa11x0_register_device(&sa11x0mcp_device, data);
}
static struct resource sa11x0ssp_resources[] = {
[0] = {
.start = 0x80070000,
.end = 0x8007ffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_Ser4SSP,
.end = IRQ_Ser4SSP,
.flags = IORESOURCE_IRQ,
},
[0] = DEFINE_RES_MEM(0x80070000, SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_Ser4SSP),
};
static u64 sa11x0ssp_dma_mask = 0xffffffffUL;
......@@ -272,16 +248,8 @@ static struct platform_device sa11x0ssp_device = {
};
static struct resource sa11x0fb_resources[] = {
[0] = {
.start = 0xb0100000,
.end = 0xb010ffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
},
[0] = DEFINE_RES_MEM(0xb0100000, SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_LCD),
};
static struct platform_device sa11x0fb_device = {
......@@ -294,6 +262,11 @@ static struct platform_device sa11x0fb_device = {
.resource = sa11x0fb_resources,
};
void sa11x0_register_lcd(struct sa1100fb_mach_info *inf)
{
sa11x0_register_device(&sa11x0fb_device, inf);
}
static struct platform_device sa11x0pcmcia_device = {
.name = "sa11x0-pcmcia",
.id = -1,
......@@ -314,23 +287,10 @@ void sa11x0_register_mtd(struct flash_platform_data *flash,
}
static struct resource sa11x0ir_resources[] = {
{
.start = __PREG(Ser2UTCR0),
.end = __PREG(Ser2UTCR0) + 0x24 - 1,
.flags = IORESOURCE_MEM,
}, {
.start = __PREG(Ser2HSCR0),
.end = __PREG(Ser2HSCR0) + 0x1c - 1,
.flags = IORESOURCE_MEM,
}, {
.start = __PREG(Ser2HSCR2),
.end = __PREG(Ser2HSCR2) + 0x04 - 1,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_Ser2ICP,
.end = IRQ_Ser2ICP,
.flags = IORESOURCE_IRQ,
}
DEFINE_RES_MEM(__PREG(Ser2UTCR0), 0x24),
DEFINE_RES_MEM(__PREG(Ser2HSCR0), 0x1c),
DEFINE_RES_MEM(__PREG(Ser2HSCR2), 0x04),
DEFINE_RES_IRQ(IRQ_Ser2ICP),
};
static struct platform_device sa11x0ir_device = {
......@@ -350,14 +310,37 @@ static struct platform_device sa11x0rtc_device = {
.id = -1,
};
static struct resource sa11x0dma_resources[] = {
DEFINE_RES_MEM(DMA_PHYS, DMA_SIZE),
DEFINE_RES_IRQ(IRQ_DMA0),
DEFINE_RES_IRQ(IRQ_DMA1),
DEFINE_RES_IRQ(IRQ_DMA2),
DEFINE_RES_IRQ(IRQ_DMA3),
DEFINE_RES_IRQ(IRQ_DMA4),
DEFINE_RES_IRQ(IRQ_DMA5),
};
static u64 sa11x0dma_dma_mask = DMA_BIT_MASK(32);
static struct platform_device sa11x0dma_device = {
.name = "sa11x0-dma",
.id = -1,
.dev = {
.dma_mask = &sa11x0dma_dma_mask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(sa11x0dma_resources),
.resource = sa11x0dma_resources,
};
static struct platform_device *sa11x0_devices[] __initdata = {
&sa11x0udc_device,
&sa11x0uart1_device,
&sa11x0uart3_device,
&sa11x0ssp_device,
&sa11x0pcmcia_device,
&sa11x0fb_device,
&sa11x0rtc_device,
&sa11x0dma_device,
};
static int __init sa1100_init(void)
......@@ -368,12 +351,6 @@ static int __init sa1100_init(void)
arch_initcall(sa1100_init);
void (*sa1100fb_backlight_power)(int on);
void (*sa1100fb_lcd_power)(int on);
EXPORT_SYMBOL(sa1100fb_backlight_power);
EXPORT_SYMBOL(sa1100fb_lcd_power);
/*
* Common I/O mapping:
......@@ -428,7 +405,7 @@ void __init sa1100_map_io(void)
* the MBGNT signal false to ensure the SA1111 doesn't own the
* SDRAM bus.
*/
void __init sa1110_mb_disable(void)
void sa1110_mb_disable(void)
{
unsigned long flags;
......@@ -447,7 +424,7 @@ void __init sa1110_mb_disable(void)
* If the system is going to use the SA-1111 DMA engines, set up
* the memory bus request/grant pins.
*/
void __devinit sa1110_mb_enable(void)
void sa1110_mb_enable(void)
{
unsigned long flags;
......
......@@ -16,9 +16,6 @@ extern void sa11x0_restart(char, const char *);
mi->bank[__nr].start = (__start), \
mi->bank[__nr].size = (__size)
extern void (*sa1100fb_backlight_power)(int on);
extern void (*sa1100fb_lcd_power)(int on);
extern void sa1110_mb_enable(void);
extern void sa1110_mb_disable(void);
......@@ -39,4 +36,8 @@ struct irda_platform_data;
void sa11x0_register_irda(struct irda_platform_data *irda);
struct mcp_plat_data;
void sa11x0_ppc_configure_mcp(void);
void sa11x0_register_mcp(struct mcp_plat_data *data);
struct sa1100fb_mach_info;
void sa11x0_register_lcd(struct sa1100fb_mach_info *inf);
......@@ -14,11 +14,14 @@
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <video/sa1100fb.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/irda.h>
#include <mach/h3xxx.h>
#include <mach/irqs.h>
#include "generic.h"
......@@ -36,13 +39,28 @@ static void h3100_lcd_power(int enable)
}
}
static struct sa1100fb_mach_info h3100_lcd_info = {
.pixclock = 406977, .bpp = 4,
.xres = 320, .yres = 240,
.hsync_len = 26, .vsync_len = 41,
.left_margin = 4, .upper_margin = 0,
.right_margin = 4, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.cmap_greyscale = 1,
.cmap_inverse = 1,
.lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
.lcd_power = h3100_lcd_power,
};
static void __init h3100_map_io(void)
{
h3xxx_map_io();
sa1100fb_lcd_power = h3100_lcd_power;
/* Older bootldrs put GPIO2-9 in alternate mode on the
assumption that they are used for video */
GAFR &= ~0x000001fb;
......@@ -80,12 +98,15 @@ static void __init h3100_mach_init(void)
{
h3xxx_init_gpio(h3100_default_gpio, ARRAY_SIZE(h3100_default_gpio));
h3xxx_mach_init();
sa11x0_register_lcd(&h3100_lcd_info);
sa11x0_register_irda(&h3100_irda_data);
}
MACHINE_START(H3100, "Compaq iPAQ H3100")
.atag_offset = 0x100,
.map_io = h3100_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = h3100_mach_init,
......
......@@ -14,11 +14,14 @@
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <video/sa1100fb.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/irda.h>
#include <mach/h3xxx.h>
#include <mach/irqs.h>
#include "generic.h"
......@@ -56,11 +59,35 @@ err2: gpio_free(H3XXX_EGPIO_LCD_ON);
err1: return;
}
static const struct sa1100fb_rgb h3600_rgb_16 = {
.red = { .offset = 12, .length = 4, },
.green = { .offset = 7, .length = 4, },
.blue = { .offset = 1, .length = 4, },
.transp = { .offset = 0, .length = 0, },
};
static struct sa1100fb_mach_info h3600_lcd_info = {
.pixclock = 174757, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 3, .vsync_len = 3,
.left_margin = 12, .upper_margin = 10,
.right_margin = 17, .lower_margin = 1,
.cmap_static = 1,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
.rgb[RGB_16] = &h3600_rgb_16,
.lcd_power = h3600_lcd_power,
};
static void __init h3600_map_io(void)
{
h3xxx_map_io();
sa1100fb_lcd_power = h3600_lcd_power;
}
/*
......@@ -121,12 +148,15 @@ static void __init h3600_mach_init(void)
{
h3xxx_init_gpio(h3600_default_gpio, ARRAY_SIZE(h3600_default_gpio));
h3xxx_mach_init();
sa11x0_register_lcd(&h3600_lcd_info);
sa11x0_register_irda(&h3600_irda_data);
}
MACHINE_START(H3600, "Compaq iPAQ H3600")
.atag_offset = 0x100,
.map_io = h3600_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = h3600_mach_init,
......
......@@ -109,11 +109,8 @@ static struct flash_platform_data h3xxx_flash_data = {
.nr_parts = ARRAY_SIZE(h3xxx_partitions),
};
static struct resource h3xxx_flash_resource = {
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
};
static struct resource h3xxx_flash_resource =
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
/*
......@@ -186,11 +183,7 @@ static struct sa1100_port_fns h3xxx_port_fns __initdata = {
*/
static struct resource egpio_resources[] = {
[0] = {
.start = H3600_EGPIO_PHYS,
.end = H3600_EGPIO_PHYS + 0x4 - 1,
.flags = IORESOURCE_MEM,
},
[0] = DEFINE_RES_MEM(H3600_EGPIO_PHYS, 0x4),
};
static struct htc_egpio_chip egpio_chips[] = {
......
......@@ -22,12 +22,10 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
......@@ -35,6 +33,9 @@
#include <asm/mach/irq.h>
#include <asm/mach/serial_sa1100.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include "generic.h"
/**********************************************************************
......@@ -179,11 +180,8 @@ static struct flash_platform_data hackkit_flash_data = {
.nr_parts = ARRAY_SIZE(hackkit_partitions),
};
static struct resource hackkit_flash_resource = {
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_32M,
.flags = IORESOURCE_MEM,
};
static struct resource hackkit_flash_resource =
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
static void __init hackkit_init(void)
{
......@@ -197,6 +195,7 @@ static void __init hackkit_init(void)
MACHINE_START(HACKKIT, "HackKit Cpu Board")
.atag_offset = 0x100,
.map_io = hackkit_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = hackkit_init,
......
......@@ -1590,224 +1590,9 @@
/*
* Direct Memory Access (DMA) control registers
*
* Registers
* DDAR0 Direct Memory Access (DMA) Device Address Register
* channel 0 (read/write).
* DCSR0 Direct Memory Access (DMA) Control and Status
* Register channel 0 (read/write).
* DBSA0 Direct Memory Access (DMA) Buffer Start address
* register A channel 0 (read/write).
* DBTA0 Direct Memory Access (DMA) Buffer Transfer count
* register A channel 0 (read/write).
* DBSB0 Direct Memory Access (DMA) Buffer Start address
* register B channel 0 (read/write).
* DBTB0 Direct Memory Access (DMA) Buffer Transfer count
* register B channel 0 (read/write).
*
* DDAR1 Direct Memory Access (DMA) Device Address Register
* channel 1 (read/write).
* DCSR1 Direct Memory Access (DMA) Control and Status
* Register channel 1 (read/write).
* DBSA1 Direct Memory Access (DMA) Buffer Start address
* register A channel 1 (read/write).
* DBTA1 Direct Memory Access (DMA) Buffer Transfer count
* register A channel 1 (read/write).
* DBSB1 Direct Memory Access (DMA) Buffer Start address
* register B channel 1 (read/write).
* DBTB1 Direct Memory Access (DMA) Buffer Transfer count
* register B channel 1 (read/write).
*
* DDAR2 Direct Memory Access (DMA) Device Address Register
* channel 2 (read/write).
* DCSR2 Direct Memory Access (DMA) Control and Status
* Register channel 2 (read/write).
* DBSA2 Direct Memory Access (DMA) Buffer Start address
* register A channel 2 (read/write).
* DBTA2 Direct Memory Access (DMA) Buffer Transfer count
* register A channel 2 (read/write).
* DBSB2 Direct Memory Access (DMA) Buffer Start address
* register B channel 2 (read/write).
* DBTB2 Direct Memory Access (DMA) Buffer Transfer count
* register B channel 2 (read/write).
*
* DDAR3 Direct Memory Access (DMA) Device Address Register
* channel 3 (read/write).
* DCSR3 Direct Memory Access (DMA) Control and Status
* Register channel 3 (read/write).
* DBSA3 Direct Memory Access (DMA) Buffer Start address
* register A channel 3 (read/write).
* DBTA3 Direct Memory Access (DMA) Buffer Transfer count
* register A channel 3 (read/write).
* DBSB3 Direct Memory Access (DMA) Buffer Start address
* register B channel 3 (read/write).
* DBTB3 Direct Memory Access (DMA) Buffer Transfer count
* register B channel 3 (read/write).
*
* DDAR4 Direct Memory Access (DMA) Device Address Register
* channel 4 (read/write).
* DCSR4 Direct Memory Access (DMA) Control and Status
* Register channel 4 (read/write).
* DBSA4 Direct Memory Access (DMA) Buffer Start address
* register A channel 4 (read/write).
* DBTA4 Direct Memory Access (DMA) Buffer Transfer count
* register A channel 4 (read/write).
* DBSB4 Direct Memory Access (DMA) Buffer Start address
* register B channel 4 (read/write).
* DBTB4 Direct Memory Access (DMA) Buffer Transfer count
* register B channel 4 (read/write).
*
* DDAR5 Direct Memory Access (DMA) Device Address Register
* channel 5 (read/write).
* DCSR5 Direct Memory Access (DMA) Control and Status
* Register channel 5 (read/write).
* DBSA5 Direct Memory Access (DMA) Buffer Start address
* register A channel 5 (read/write).
* DBTA5 Direct Memory Access (DMA) Buffer Transfer count
* register A channel 5 (read/write).
* DBSB5 Direct Memory Access (DMA) Buffer Start address
* register B channel 5 (read/write).
* DBTB5 Direct Memory Access (DMA) Buffer Transfer count
* register B channel 5 (read/write).
*/
#define DMASp 0x00000020 /* DMA control reg. Space [byte] */
#define DDAR(Nb) __REG(0xB0000000 + (Nb)*DMASp) /* DMA Device Address Reg. channel [0..5] */
#define SetDCSR(Nb) __REG(0xB0000004 + (Nb)*DMASp) /* Set DMA Control & Status Reg. channel [0..5] (write) */
#define ClrDCSR(Nb) __REG(0xB0000008 + (Nb)*DMASp) /* Clear DMA Control & Status Reg. channel [0..5] (write) */
#define RdDCSR(Nb) __REG(0xB000000C + (Nb)*DMASp) /* Read DMA Control & Status Reg. channel [0..5] (read) */
#define DBSA(Nb) __REG(0xB0000010 + (Nb)*DMASp) /* DMA Buffer Start address reg. A channel [0..5] */
#define DBTA(Nb) __REG(0xB0000014 + (Nb)*DMASp) /* DMA Buffer Transfer count reg. A channel [0..5] */
#define DBSB(Nb) __REG(0xB0000018 + (Nb)*DMASp) /* DMA Buffer Start address reg. B channel [0..5] */
#define DBTB(Nb) __REG(0xB000001C + (Nb)*DMASp) /* DMA Buffer Transfer count reg. B channel [0..5] */
#define DDAR_RW 0x00000001 /* device data Read/Write */
#define DDAR_DevWr (DDAR_RW*0) /* Device data Write */
/* (memory -> device) */
#define DDAR_DevRd (DDAR_RW*1) /* Device data Read */
/* (device -> memory) */
#define DDAR_E 0x00000002 /* big/little Endian device */
#define DDAR_LtlEnd (DDAR_E*0) /* Little Endian device */
#define DDAR_BigEnd (DDAR_E*1) /* Big Endian device */
#define DDAR_BS 0x00000004 /* device Burst Size */
#define DDAR_Brst4 (DDAR_BS*0) /* Burst-of-4 device */
#define DDAR_Brst8 (DDAR_BS*1) /* Burst-of-8 device */
#define DDAR_DW 0x00000008 /* device Data Width */
#define DDAR_8BitDev (DDAR_DW*0) /* 8-Bit Device */
#define DDAR_16BitDev (DDAR_DW*1) /* 16-Bit Device */
#define DDAR_DS Fld (4, 4) /* Device Select */
#define DDAR_Ser0UDCTr /* Ser. port 0 UDC Transmit */ \
(0x0 << FShft (DDAR_DS))
#define DDAR_Ser0UDCRc /* Ser. port 0 UDC Receive */ \
(0x1 << FShft (DDAR_DS))
#define DDAR_Ser1SDLCTr /* Ser. port 1 SDLC Transmit */ \
(0x2 << FShft (DDAR_DS))
#define DDAR_Ser1SDLCRc /* Ser. port 1 SDLC Receive */ \
(0x3 << FShft (DDAR_DS))
#define DDAR_Ser1UARTTr /* Ser. port 1 UART Transmit */ \
(0x4 << FShft (DDAR_DS))
#define DDAR_Ser1UARTRc /* Ser. port 1 UART Receive */ \
(0x5 << FShft (DDAR_DS))
#define DDAR_Ser2ICPTr /* Ser. port 2 ICP Transmit */ \
(0x6 << FShft (DDAR_DS))
#define DDAR_Ser2ICPRc /* Ser. port 2 ICP Receive */ \
(0x7 << FShft (DDAR_DS))
#define DDAR_Ser3UARTTr /* Ser. port 3 UART Transmit */ \
(0x8 << FShft (DDAR_DS))
#define DDAR_Ser3UARTRc /* Ser. port 3 UART Receive */ \
(0x9 << FShft (DDAR_DS))
#define DDAR_Ser4MCP0Tr /* Ser. port 4 MCP 0 Transmit */ \
/* (audio) */ \
(0xA << FShft (DDAR_DS))
#define DDAR_Ser4MCP0Rc /* Ser. port 4 MCP 0 Receive */ \
/* (audio) */ \
(0xB << FShft (DDAR_DS))
#define DDAR_Ser4MCP1Tr /* Ser. port 4 MCP 1 Transmit */ \
/* (telecom) */ \
(0xC << FShft (DDAR_DS))
#define DDAR_Ser4MCP1Rc /* Ser. port 4 MCP 1 Receive */ \
/* (telecom) */ \
(0xD << FShft (DDAR_DS))
#define DDAR_Ser4SSPTr /* Ser. port 4 SSP Transmit */ \
(0xE << FShft (DDAR_DS))
#define DDAR_Ser4SSPRc /* Ser. port 4 SSP Receive */ \
(0xF << FShft (DDAR_DS))
#define DDAR_DA Fld (24, 8) /* Device Address */
#define DDAR_DevAdd(Add) /* Device Address */ \
(((Add) & 0xF0000000) | \
(((Add) & 0X003FFFFC) << (FShft (DDAR_DA) - 2)))
#define DDAR_Ser0UDCWr /* Ser. port 0 UDC Write */ \
(DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \
DDAR_Ser0UDCTr + DDAR_DevAdd (__PREG(Ser0UDCDR)))
#define DDAR_Ser0UDCRd /* Ser. port 0 UDC Read */ \
(DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \
DDAR_Ser0UDCRc + DDAR_DevAdd (__PREG(Ser0UDCDR)))
#define DDAR_Ser1UARTWr /* Ser. port 1 UART Write */ \
(DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
DDAR_Ser1UARTTr + DDAR_DevAdd (__PREG(Ser1UTDR)))
#define DDAR_Ser1UARTRd /* Ser. port 1 UART Read */ \
(DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
DDAR_Ser1UARTRc + DDAR_DevAdd (__PREG(Ser1UTDR)))
#define DDAR_Ser1SDLCWr /* Ser. port 1 SDLC Write */ \
(DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
DDAR_Ser1SDLCTr + DDAR_DevAdd (__PREG(Ser1SDDR)))
#define DDAR_Ser1SDLCRd /* Ser. port 1 SDLC Read */ \
(DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
DDAR_Ser1SDLCRc + DDAR_DevAdd (__PREG(Ser1SDDR)))
#define DDAR_Ser2UARTWr /* Ser. port 2 UART Write */ \
(DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2UTDR)))
#define DDAR_Ser2UARTRd /* Ser. port 2 UART Read */ \
(DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2UTDR)))
#define DDAR_Ser2HSSPWr /* Ser. port 2 HSSP Write */ \
(DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \
DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2HSDR)))
#define DDAR_Ser2HSSPRd /* Ser. port 2 HSSP Read */ \
(DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \
DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2HSDR)))
#define DDAR_Ser3UARTWr /* Ser. port 3 UART Write */ \
(DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
DDAR_Ser3UARTTr + DDAR_DevAdd (__PREG(Ser3UTDR)))
#define DDAR_Ser3UARTRd /* Ser. port 3 UART Read */ \
(DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
DDAR_Ser3UARTRc + DDAR_DevAdd (__PREG(Ser3UTDR)))
#define DDAR_Ser4MCP0Wr /* Ser. port 4 MCP 0 Write (audio) */ \
(DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
DDAR_Ser4MCP0Tr + DDAR_DevAdd (__PREG(Ser4MCDR0)))
#define DDAR_Ser4MCP0Rd /* Ser. port 4 MCP 0 Read (audio) */ \
(DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
DDAR_Ser4MCP0Rc + DDAR_DevAdd (__PREG(Ser4MCDR0)))
#define DDAR_Ser4MCP1Wr /* Ser. port 4 MCP 1 Write */ \
/* (telecom) */ \
(DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
DDAR_Ser4MCP1Tr + DDAR_DevAdd (__PREG(Ser4MCDR1)))
#define DDAR_Ser4MCP1Rd /* Ser. port 4 MCP 1 Read */ \
/* (telecom) */ \
(DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
DDAR_Ser4MCP1Rc + DDAR_DevAdd (__PREG(Ser4MCDR1)))
#define DDAR_Ser4SSPWr /* Ser. port 4 SSP Write (16 bits) */ \
(DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
DDAR_Ser4SSPTr + DDAR_DevAdd (__PREG(Ser4SSDR)))
#define DDAR_Ser4SSPRd /* Ser. port 4 SSP Read (16 bits) */ \
(DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
DDAR_Ser4SSPRc + DDAR_DevAdd (__PREG(Ser4SSDR)))
#define DCSR_RUN 0x00000001 /* DMA running */
#define DCSR_IE 0x00000002 /* DMA Interrupt Enable */
#define DCSR_ERROR 0x00000004 /* DMA ERROR */
#define DCSR_DONEA 0x00000008 /* DONE DMA transfer buffer A */
#define DCSR_STRTA 0x00000010 /* STaRTed DMA transfer buffer A */
#define DCSR_DONEB 0x00000020 /* DONE DMA transfer buffer B */
#define DCSR_STRTB 0x00000040 /* STaRTed DMA transfer buffer B */
#define DCSR_BIU 0x00000080 /* DMA Buffer In Use */
#define DCSR_BufA (DCSR_BIU*0) /* DMA Buffer A in use */
#define DCSR_BufB (DCSR_BIU*1) /* DMA Buffer B in use */
#define DBT_TC Fld (13, 0) /* Transfer Count */
#define DBTA_TCA DBT_TC /* Transfer Count buffer A */
#define DBTB_TCB DBT_TC /* Transfer Count buffer B */
#define DMA_SIZE (6 * 0x20)
#define DMA_PHYS 0xb0000000
/*
......@@ -1903,16 +1688,6 @@
#define LCD_Int100_0A 0xF /* LCD Intensity = 100.0% = 1 */
/* (Alternative) */
#define LCCR0 __REG(0xB0100000) /* LCD Control Reg. 0 */
#define LCSR __REG(0xB0100004) /* LCD Status Reg. */
#define DBAR1 __REG(0xB0100010) /* LCD DMA Base Address Reg. channel 1 */
#define DCAR1 __REG(0xB0100014) /* LCD DMA Current Address Reg. channel 1 */
#define DBAR2 __REG(0xB0100018) /* LCD DMA Base Address Reg. channel 2 */
#define DCAR2 __REG(0xB010001C) /* LCD DMA Current Address Reg. channel 2 */
#define LCCR1 __REG(0xB0100020) /* LCD Control Reg. 1 */
#define LCCR2 __REG(0xB0100024) /* LCD Control Reg. 2 */
#define LCCR3 __REG(0xB0100028) /* LCD Control Reg. 3 */
#define LCCR0_LEN 0x00000001 /* LCD ENable */
#define LCCR0_CMS 0x00000002 /* Color/Monochrome display Select */
#define LCCR0_Color (LCCR0_CMS*0) /* Color display */
......
/*
* arch/arm/mach-sa1100/include/mach/dma.h
*
* Generic SA1100 DMA support
*
* Copyright (C) 2000 Nicolas Pitre
*
*/
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H
#include "hardware.h"
/*
* The SA1100 has six internal DMA channels.
*/
#define SA1100_DMA_CHANNELS 6
/*
* Maximum physical DMA buffer size
*/
#define MAX_DMA_SIZE 0x1fff
#define CUT_DMA_SIZE 0x1000
/*
* All possible SA1100 devices a DMA channel can be attached to.
*/
typedef enum {
DMA_Ser0UDCWr = DDAR_Ser0UDCWr, /* Ser. port 0 UDC Write */
DMA_Ser0UDCRd = DDAR_Ser0UDCRd, /* Ser. port 0 UDC Read */
DMA_Ser1UARTWr = DDAR_Ser1UARTWr, /* Ser. port 1 UART Write */
DMA_Ser1UARTRd = DDAR_Ser1UARTRd, /* Ser. port 1 UART Read */
DMA_Ser1SDLCWr = DDAR_Ser1SDLCWr, /* Ser. port 1 SDLC Write */
DMA_Ser1SDLCRd = DDAR_Ser1SDLCRd, /* Ser. port 1 SDLC Read */
DMA_Ser2UARTWr = DDAR_Ser2UARTWr, /* Ser. port 2 UART Write */
DMA_Ser2UARTRd = DDAR_Ser2UARTRd, /* Ser. port 2 UART Read */
DMA_Ser2HSSPWr = DDAR_Ser2HSSPWr, /* Ser. port 2 HSSP Write */
DMA_Ser2HSSPRd = DDAR_Ser2HSSPRd, /* Ser. port 2 HSSP Read */
DMA_Ser3UARTWr = DDAR_Ser3UARTWr, /* Ser. port 3 UART Write */
DMA_Ser3UARTRd = DDAR_Ser3UARTRd, /* Ser. port 3 UART Read */
DMA_Ser4MCP0Wr = DDAR_Ser4MCP0Wr, /* Ser. port 4 MCP 0 Write (audio) */
DMA_Ser4MCP0Rd = DDAR_Ser4MCP0Rd, /* Ser. port 4 MCP 0 Read (audio) */
DMA_Ser4MCP1Wr = DDAR_Ser4MCP1Wr, /* Ser. port 4 MCP 1 Write */
DMA_Ser4MCP1Rd = DDAR_Ser4MCP1Rd, /* Ser. port 4 MCP 1 Read */
DMA_Ser4SSPWr = DDAR_Ser4SSPWr, /* Ser. port 4 SSP Write (16 bits) */
DMA_Ser4SSPRd = DDAR_Ser4SSPRd /* Ser. port 4 SSP Read (16 bits) */
} dma_device_t;
typedef struct {
volatile u_long DDAR;
volatile u_long SetDCSR;
volatile u_long ClrDCSR;
volatile u_long RdDCSR;
volatile dma_addr_t DBSA;
volatile u_long DBTA;
volatile dma_addr_t DBSB;
volatile u_long DBTB;
} dma_regs_t;
typedef void (*dma_callback_t)(void *data);
/*
* DMA function prototypes
*/
extern int sa1100_request_dma( dma_device_t device, const char *device_id,
dma_callback_t callback, void *data,
dma_regs_t **regs );
extern void sa1100_free_dma( dma_regs_t *regs );
extern int sa1100_start_dma( dma_regs_t *regs, dma_addr_t dma_ptr, u_int size );
extern dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs);
extern void sa1100_reset_dma(dma_regs_t *regs);
/**
* sa1100_stop_dma - stop DMA in progress
* @regs: identifier for the channel to use
*
* This stops DMA without clearing buffer pointers. Unlike
* sa1100_clear_dma() this allows subsequent use of sa1100_resume_dma()
* or sa1100_get_dma_pos().
*
* The @regs identifier is provided by a successful call to
* sa1100_request_dma().
**/
#define sa1100_stop_dma(regs) ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN)
/**
* sa1100_resume_dma - resume DMA on a stopped channel
* @regs: identifier for the channel to use
*
* This resumes DMA on a channel previously stopped with
* sa1100_stop_dma().
*
* The @regs identifier is provided by a successful call to
* sa1100_request_dma().
**/
#define sa1100_resume_dma(regs) ((regs)->SetDCSR = DCSR_IE|DCSR_RUN)
/**
* sa1100_clear_dma - clear DMA pointers
* @regs: identifier for the channel to use
*
* This clear any DMA state so the DMA engine is ready to restart
* with new buffers through sa1100_start_dma(). Any buffers in flight
* are discarded.
*
* The @regs identifier is provided by a successful call to
* sa1100_request_dma().
**/
#define sa1100_clear_dma(regs) ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN|DCSR_STRTA|DCSR_STRTB)
#endif /* _ASM_ARCH_DMA_H */
......@@ -71,22 +71,19 @@
/*
* Figure out the MAX IRQ number.
*
* If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1.
* If we have an LoCoMo, the max IRQ is IRQ_BOARD_START + 4
* Otherwise, we have the standard IRQs only.
* Neponset, SA1111 and UCB1x00 are sparse IRQ aware, so can dynamically
* allocate their IRQs above NR_IRQS.
*
* LoCoMo has 4 additional IRQs, but is not sparse IRQ aware, and so has
* to be included in the NR_IRQS calculation.
*/
#ifdef CONFIG_SA1111
#define NR_IRQS (IRQ_BOARD_END + 55)
#elif defined(CONFIG_SHARP_LOCOMO)
#define NR_IRQS (IRQ_BOARD_START + 4)
#ifdef CONFIG_SHARP_LOCOMO
#define NR_IRQS_LOCOMO 4
#else
#define NR_IRQS (IRQ_BOARD_START)
#define NR_IRQS_LOCOMO 0
#endif
/*
* Board specific IRQs. Define them here.
* Do not surround them with ifdefs.
*/
#define IRQ_NEPONSET_SMC9196 (IRQ_BOARD_START + 0)
#define IRQ_NEPONSET_USAR (IRQ_BOARD_START + 1)
#define IRQ_NEPONSET_SA1111 (IRQ_BOARD_START + 2)
#ifndef NR_IRQS
#define NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
#endif
#define SA1100_NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
......@@ -16,7 +16,7 @@ struct mcp_plat_data {
u32 mccr0;
u32 mccr1;
unsigned int sclk_rate;
int gpio_base;
void *codec_pdata;
};
#endif
......@@ -15,54 +15,6 @@
/*
* Neponset definitions:
*/
#define NEPONSET_CPLD_BASE (0x10000000)
#define Nep_p2v( x ) ((x) - NEPONSET_CPLD_BASE + 0xf3000000)
#define Nep_v2p( x ) ((x) - 0xf3000000 + NEPONSET_CPLD_BASE)
#define _IRR 0x10000024 /* Interrupt Reason Register */
#define _AUD_CTL 0x100000c0 /* Audio controls (RW) */
#define _MDM_CTL_0 0x100000b0 /* Modem control 0 (RW) */
#define _MDM_CTL_1 0x100000b4 /* Modem control 1 (RW) */
#define _NCR_0 0x100000a0 /* Control Register (RW) */
#define _KP_X_OUT 0x10000090 /* Keypad row write (RW) */
#define _KP_Y_IN 0x10000080 /* Keypad column read (RO) */
#define _SWPK 0x10000020 /* Switch pack (RO) */
#define _WHOAMI 0x10000000 /* System ID Register (RO) */
#define _LEDS 0x10000010 /* LEDs [31:0] (WO) */
#define IRR (*((volatile u_char *) Nep_p2v(_IRR)))
#define AUD_CTL (*((volatile u_char *) Nep_p2v(_AUD_CTL)))
#define MDM_CTL_0 (*((volatile u_char *) Nep_p2v(_MDM_CTL_0)))
#define MDM_CTL_1 (*((volatile u_char *) Nep_p2v(_MDM_CTL_1)))
#define NCR_0 (*((volatile u_char *) Nep_p2v(_NCR_0)))
#define KP_X_OUT (*((volatile u_char *) Nep_p2v(_KP_X_OUT)))
#define KP_Y_IN (*((volatile u_char *) Nep_p2v(_KP_Y_IN)))
#define SWPK (*((volatile u_char *) Nep_p2v(_SWPK)))
#define WHOAMI (*((volatile u_char *) Nep_p2v(_WHOAMI)))
#define LEDS (*((volatile Word *) Nep_p2v(_LEDS)))
#define IRR_ETHERNET (1<<0)
#define IRR_USAR (1<<1)
#define IRR_SA1111 (1<<2)
#define AUD_SEL_1341 (1<<0)
#define AUD_MUTE_1341 (1<<1)
#define MDM_CTL0_RTS1 (1 << 0)
#define MDM_CTL0_DTR1 (1 << 1)
#define MDM_CTL0_RTS2 (1 << 2)
#define MDM_CTL0_DTR2 (1 << 3)
#define MDM_CTL1_CTS1 (1 << 0)
#define MDM_CTL1_DSR1 (1 << 1)
#define MDM_CTL1_DCD1 (1 << 2)
#define MDM_CTL1_CTS2 (1 << 3)
#define MDM_CTL1_DSR2 (1 << 4)
#define MDM_CTL1_DCD2 (1 << 5)
#define NCR_GP01_OFF (1<<0)
#define NCR_TP_PWR_EN (1<<1)
#define NCR_MS_PWR_EN (1<<2)
......@@ -71,4 +23,8 @@
#define NCR_A0VPP (1<<5)
#define NCR_A1VPP (1<<6)
void neponset_ncr_frob(unsigned int, unsigned int);
#define neponset_ncr_set(v) neponset_ncr_frob(0, v)
#define neponset_ncr_clear(v) neponset_ncr_frob(v, 0)
#endif
......@@ -21,7 +21,7 @@
#define SHANNON_GPIO_U3_RTS GPIO_GPIO (19) /* ?? */
#define SHANNON_GPIO_U3_CTS GPIO_GPIO (20) /* ?? */
#define SHANNON_GPIO_SENSE_12V GPIO_GPIO (21) /* Input, 12v flash unprotect detected */
#define SHANNON_GPIO_DISP_EN GPIO_GPIO (22) /* out */
#define SHANNON_GPIO_DISP_EN 22 /* out */
/* XXX GPIO 23 unaccounted for */
#define SHANNON_GPIO_EJECT_0 GPIO_GPIO (24) /* in */
#define SHANNON_IRQ_GPIO_EJECT_0 IRQ_GPIO24
......
......@@ -17,6 +17,7 @@
#include <linux/syscore_ops.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <asm/mach/irq.h>
#include "generic.h"
......@@ -221,11 +222,8 @@ static struct irq_chip sa1100_normal_chip = {
.irq_set_wake = sa1100_set_wake,
};
static struct resource irq_resource = {
.name = "irqs",
.start = 0x90050000,
.end = 0x9005ffff,
};
static struct resource irq_resource =
DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
static struct sa1100irq_state {
unsigned int saved;
......
......@@ -23,9 +23,7 @@
#include <linux/mtd/partitions.h>
#include <video/s1d13xxxfb.h>
#include <mach/hardware.h>
#include <asm/hardware/sa1111.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
......@@ -34,6 +32,9 @@
#include <asm/mach/map.h>
#include <asm/mach/serial_sa1100.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include "generic.h"
/*
......@@ -46,7 +47,7 @@
/* memory space (line 52 of HP's doc) */
#define SA1111REGSTART 0x40000000
#define SA1111REGLEN 0x00001fff
#define SA1111REGLEN 0x00002000
#define EPSONREGSTART 0x48000000
#define EPSONREGLEN 0x00100000
#define EPSONFBSTART 0x48200000
......@@ -174,16 +175,8 @@ static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
};
static struct resource s1d13xxxfb_resources[] = {
[0] = {
.start = EPSONFBSTART,
.end = EPSONFBSTART + EPSONFBLEN,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = EPSONREGSTART,
.end = EPSONREGSTART + EPSONREGLEN,
.flags = IORESOURCE_MEM,
}
[0] = DEFINE_RES_MEM(EPSONFBSTART, EPSONFBLEN),
[1] = DEFINE_RES_MEM(EPSONREGSTART, EPSONREGLEN),
};
static struct platform_device s1d13xxxfb_device = {
......@@ -197,20 +190,12 @@ static struct platform_device s1d13xxxfb_device = {
};
static struct resource sa1111_resources[] = {
[0] = {
.start = SA1111REGSTART,
.end = SA1111REGSTART + SA1111REGLEN,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_GPIO1,
.end = IRQ_GPIO1,
.flags = IORESOURCE_IRQ,
},
[0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
[1] = DEFINE_RES_IRQ(IRQ_GPIO1),
};
static struct sa1111_platform_data sa1111_info = {
.irq_base = IRQ_BOARD_END,
.disable_devs = SA1111_DEVID_PS2_MSE,
};
static u64 sa1111_dmamask = 0xffffffffUL;
......@@ -284,11 +269,6 @@ static struct map_desc jornada720_io_desc[] __initdata = {
.pfn = __phys_to_pfn(EPSONFBSTART),
.length = EPSONFBLEN,
.type = MT_DEVICE
}, { /* SA-1111 */
.virtual = 0xf4000000,
.pfn = __phys_to_pfn(SA1111REGSTART),
.length = SA1111REGLEN,
.type = MT_DEVICE
}
};
......@@ -352,11 +332,8 @@ static struct flash_platform_data jornada720_flash_data = {
.nr_parts = ARRAY_SIZE(jornada720_partitions),
};
static struct resource jornada720_flash_resource = {
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
};
static struct resource jornada720_flash_resource =
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
static void __init jornada720_mach_init(void)
{
......@@ -367,6 +344,7 @@ MACHINE_START(JORNADA720, "HP Jornada 720")
/* Maintainer: Kristoffer Ericson <Kristoffer.Ericson@gmail.com> */
.atag_offset = 0x100,
.map_io = jornada720_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = jornada720_mach_init,
......
......@@ -6,6 +6,8 @@
#include <linux/kernel.h>
#include <linux/tty.h>
#include <video/sa1100fb.h>
#include <mach/hardware.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
......@@ -15,6 +17,7 @@
#include <asm/mach/map.h>
#include <asm/mach/serial_sa1100.h>
#include <mach/mcp.h>
#include <mach/irqs.h>
#include "generic.h"
......@@ -26,8 +29,86 @@ static struct mcp_plat_data lart_mcp_data = {
.sclk_rate = 11981000,
};
#ifdef LART_GREY_LCD
static struct sa1100fb_mach_info lart_grey_info = {
.pixclock = 150000, .bpp = 4,
.xres = 320, .yres = 240,
.hsync_len = 1, .vsync_len = 1,
.left_margin = 4, .upper_margin = 0,
.right_margin = 2, .lower_margin = 0,
.cmap_greyscale = 1,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
};
#endif
#ifdef LART_COLOR_LCD
static struct sa1100fb_mach_info lart_color_info = {
.pixclock = 150000, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 2, .vsync_len = 3,
.left_margin = 69, .upper_margin = 14,
.right_margin = 8, .lower_margin = 4,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
};
#endif
#ifdef LART_VIDEO_OUT
static struct sa1100fb_mach_info lart_video_info = {
.pixclock = 39721, .bpp = 16,
.xres = 640, .yres = 480,
.hsync_len = 95, .vsync_len = 2,
.left_margin = 40, .upper_margin = 32,
.right_margin = 24, .lower_margin = 11,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
};
#endif
#ifdef LART_KIT01_LCD
static struct sa1100fb_mach_info lart_kit01_info = {
.pixclock = 63291, .bpp = 16,
.xres = 640, .yres = 480,
.hsync_len = 64, .vsync_len = 3,
.left_margin = 122, .upper_margin = 45,
.right_margin = 10, .lower_margin = 10,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg
};
#endif
static void __init lart_init(void)
{
struct sa1100fb_mach_info *inf = NULL;
#ifdef LART_GREY_LCD
inf = &lart_grey_info;
#endif
#ifdef LART_COLOR_LCD
inf = &lart_color_info;
#endif
#ifdef LART_VIDEO_OUT
inf = &lart_video_info;
#endif
#ifdef LART_KIT01_LCD
inf = &lart_kit01_info;
#endif
if (inf)
sa11x0_register_lcd(inf);
sa11x0_ppc_configure_mcp();
sa11x0_register_mcp(&lart_mcp_data);
}
......@@ -63,6 +144,7 @@ static void __init lart_map_io(void)
MACHINE_START(LART, "LART")
.atag_offset = 0x100,
.map_io = lart_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.init_machine = lart_init,
.timer = &sa1100_timer,
......
......@@ -28,6 +28,7 @@
#include <mach/hardware.h>
#include <mach/nanoengine.h>
#include <mach/irqs.h>
#include "generic.h"
......@@ -58,15 +59,8 @@ static struct flash_platform_data nanoengine_flash_data = {
};
static struct resource nanoengine_flash_resources[] = {
{
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
}, {
.start = SA1100_CS1_PHYS,
.end = SA1100_CS1_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
}
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M),
};
static struct map_desc nanoengine_io_desc[] __initdata = {
......@@ -114,6 +108,7 @@ static void __init nanoengine_init(void)
MACHINE_START(NANOENGINE, "BSE nanoEngine")
.atag_offset = 0x100,
.map_io = nanoengine_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = nanoengine_init,
......
/*
* linux/arch/arm/mach-sa1100/neponset.c
*
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/serial_core.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/irq.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <asm/mach/serial_sa1100.h>
#include <mach/assabet.h>
#include <mach/neponset.h>
#include <asm/hardware/sa1111.h>
#include <asm/sizes.h>
/*
* Install handler for Neponset IRQ. Note that we have to loop here
* since the ETHERNET and USAR IRQs are level based, and we need to
* ensure that the IRQ signal is deasserted before returning. This
* is rather unfortunate.
*/
static void
neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned int irr;
while (1) {
/*
* Acknowledge the parent IRQ.
*/
desc->irq_data.chip->irq_ack(&desc->irq_data);
/*
* Read the interrupt reason register. Let's have all
* active IRQ bits high. Note: there is a typo in the
* Neponset user's guide for the SA1111 IRR level.
*/
irr = IRR ^ (IRR_ETHERNET | IRR_USAR);
if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
break;
/*
* Since there is no individual mask, we have to
* mask the parent IRQ. This is safe, since we'll
* recheck the register for any pending IRQs.
*/
if (irr & (IRR_ETHERNET | IRR_USAR)) {
desc->irq_data.chip->irq_mask(&desc->irq_data);
/*
* Ack the interrupt now to prevent re-entering
* this neponset handler. Again, this is safe
* since we'll check the IRR register prior to
* leaving.
*/
desc->irq_data.chip->irq_ack(&desc->irq_data);
#include <mach/hardware.h>
#include <mach/assabet.h>
#include <mach/neponset.h>
#include <mach/irqs.h>
#define NEP_IRQ_SMC91X 0
#define NEP_IRQ_USAR 1
#define NEP_IRQ_SA1111 2
#define NEP_IRQ_NR 3
#define WHOAMI 0x00
#define LEDS 0x10
#define SWPK 0x20
#define IRR 0x24
#define KP_Y_IN 0x80
#define KP_X_OUT 0x90
#define NCR_0 0xa0
#define MDM_CTL_0 0xb0
#define MDM_CTL_1 0xb4
#define AUD_CTL 0xc0
#define IRR_ETHERNET (1 << 0)
#define IRR_USAR (1 << 1)
#define IRR_SA1111 (1 << 2)
#define MDM_CTL0_RTS1 (1 << 0)
#define MDM_CTL0_DTR1 (1 << 1)
#define MDM_CTL0_RTS2 (1 << 2)
#define MDM_CTL0_DTR2 (1 << 3)
#define MDM_CTL1_CTS1 (1 << 0)
#define MDM_CTL1_DSR1 (1 << 1)
#define MDM_CTL1_DCD1 (1 << 2)
#define MDM_CTL1_CTS2 (1 << 3)
#define MDM_CTL1_DSR2 (1 << 4)
#define MDM_CTL1_DCD2 (1 << 5)
#define AUD_SEL_1341 (1 << 0)
#define AUD_MUTE_1341 (1 << 1)
if (irr & IRR_ETHERNET) {
generic_handle_irq(IRQ_NEPONSET_SMC9196);
}
extern void sa1110_mb_disable(void);
if (irr & IRR_USAR) {
generic_handle_irq(IRQ_NEPONSET_USAR);
}
struct neponset_drvdata {
void __iomem *base;
struct platform_device *sa1111;
struct platform_device *smc91x;
unsigned irq_base;
#ifdef CONFIG_PM_SLEEP
u32 ncr0;
u32 mdm_ctl_0;
#endif
};
desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
static void __iomem *nep_base;
if (irr & IRR_SA1111) {
generic_handle_irq(IRQ_NEPONSET_SA1111);
}
void neponset_ncr_frob(unsigned int mask, unsigned int val)
{
void __iomem *base = nep_base;
if (base) {
unsigned long flags;
unsigned v;
local_irq_save(flags);
v = readb_relaxed(base + NCR_0);
writeb_relaxed((v & ~mask) | val, base + NCR_0);
local_irq_restore(flags);
} else {
WARN(1, "nep_base unset\n");
}
}
static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
{
u_int mdm_ctl0 = MDM_CTL_0;
void __iomem *base = nep_base;
u_int mdm_ctl0;
if (!base)
return;
mdm_ctl0 = readb_relaxed(base + MDM_CTL_0);
if (port->mapbase == _Ser1UTCR0) {
if (mctrl & TIOCM_RTS)
mdm_ctl0 &= ~MDM_CTL0_RTS2;
......@@ -106,14 +121,19 @@ static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
mdm_ctl0 |= MDM_CTL0_DTR1;
}
MDM_CTL_0 = mdm_ctl0;
writeb_relaxed(mdm_ctl0, base + MDM_CTL_0);
}
static u_int neponset_get_mctrl(struct uart_port *port)
{
void __iomem *base = nep_base;
u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
u_int mdm_ctl1 = MDM_CTL_1;
u_int mdm_ctl1;
if (!base)
return ret;
mdm_ctl1 = readb_relaxed(base + MDM_CTL_1);
if (port->mapbase == _Ser1UTCR0) {
if (mdm_ctl1 & MDM_CTL1_DCD2)
ret &= ~TIOCM_CD;
......@@ -138,209 +158,278 @@ static struct sa1100_port_fns neponset_port_fns __devinitdata = {
.get_mctrl = neponset_get_mctrl,
};
static int __devinit neponset_probe(struct platform_device *dev)
/*
* Install handler for Neponset IRQ. Note that we have to loop here
* since the ETHERNET and USAR IRQs are level based, and we need to
* ensure that the IRQ signal is deasserted before returning. This
* is rather unfortunate.
*/
static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
{
sa1100_register_uart_fns(&neponset_port_fns);
struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
unsigned int irr;
while (1) {
/*
* Install handler for GPIO25.
* Acknowledge the parent IRQ.
*/
irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING);
irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler);
desc->irq_data.chip->irq_ack(&desc->irq_data);
/*
* We would set IRQ_GPIO25 to be a wake-up IRQ, but
* unfortunately something on the Neponset activates
* this IRQ on sleep (ethernet?)
* Read the interrupt reason register. Let's have all
* active IRQ bits high. Note: there is a typo in the
* Neponset user's guide for the SA1111 IRR level.
*/
#if 0
enable_irq_wake(IRQ_GPIO25);
#endif
irr = readb_relaxed(d->base + IRR);
irr ^= IRR_ETHERNET | IRR_USAR;
if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
break;
/*
* Setup other Neponset IRQs. SA1111 will be done by the
* generic SA1111 code.
* Since there is no individual mask, we have to
* mask the parent IRQ. This is safe, since we'll
* recheck the register for any pending IRQs.
*/
irq_set_handler(IRQ_NEPONSET_SMC9196, handle_simple_irq);
set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
irq_set_handler(IRQ_NEPONSET_USAR, handle_simple_irq);
set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
if (irr & (IRR_ETHERNET | IRR_USAR)) {
desc->irq_data.chip->irq_mask(&desc->irq_data);
/*
* Disable GPIO 0/1 drivers so the buttons work on the module.
* Ack the interrupt now to prevent re-entering
* this neponset handler. Again, this is safe
* since we'll check the IRR register prior to
* leaving.
*/
NCR_0 = NCR_GP01_OFF;
return 0;
}
desc->irq_data.chip->irq_ack(&desc->irq_data);
#ifdef CONFIG_PM
if (irr & IRR_ETHERNET)
generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
/*
* LDM power management.
*/
static unsigned int neponset_saved_state;
if (irr & IRR_USAR)
generic_handle_irq(d->irq_base + NEP_IRQ_USAR);
static int neponset_suspend(struct platform_device *dev, pm_message_t state)
{
/*
* Save state.
*/
neponset_saved_state = NCR_0;
desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
return 0;
if (irr & IRR_SA1111)
generic_handle_irq(d->irq_base + NEP_IRQ_SA1111);
}
}
static int neponset_resume(struct platform_device *dev)
/* Yes, we really do not have any kind of masking or unmasking */
static void nochip_noop(struct irq_data *irq)
{
NCR_0 = neponset_saved_state;
return 0;
}
#else
#define neponset_suspend NULL
#define neponset_resume NULL
#endif
static struct platform_driver neponset_device_driver = {
.probe = neponset_probe,
.suspend = neponset_suspend,
.resume = neponset_resume,
.driver = {
.name = "neponset",
},
};
static struct resource neponset_resources[] = {
[0] = {
.start = 0x10000000,
.end = 0x17ffffff,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device neponset_device = {
static struct irq_chip nochip = {
.name = "neponset",
.id = 0,
.num_resources = ARRAY_SIZE(neponset_resources),
.resource = neponset_resources,
};
static struct resource sa1111_resources[] = {
[0] = {
.start = 0x40000000,
.end = 0x40001fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_NEPONSET_SA1111,
.end = IRQ_NEPONSET_SA1111,
.flags = IORESOURCE_IRQ,
},
.irq_ack = nochip_noop,
.irq_mask = nochip_noop,
.irq_unmask = nochip_noop,
};
static struct sa1111_platform_data sa1111_info = {
.irq_base = IRQ_BOARD_END,
.disable_devs = SA1111_DEVID_PS2_MSE,
};
static u64 sa1111_dmamask = 0xffffffffUL;
static struct platform_device sa1111_device = {
static int __devinit neponset_probe(struct platform_device *dev)
{
struct neponset_drvdata *d;
struct resource *nep_res, *sa1111_res, *smc91x_res;
struct resource sa1111_resources[] = {
DEFINE_RES_MEM(0x40000000, SZ_8K),
{ .flags = IORESOURCE_IRQ },
};
struct platform_device_info sa1111_devinfo = {
.parent = &dev->dev,
.name = "sa1111",
.id = 0,
.dev = {
.dma_mask = &sa1111_dmamask,
.coherent_dma_mask = 0xffffffff,
.platform_data = &sa1111_info,
},
.num_resources = ARRAY_SIZE(sa1111_resources),
.resource = sa1111_resources,
};
static struct resource smc91x_resources[] = {
[0] = {
.name = "smc91x-regs",
.start = SA1100_CS3_PHYS,
.end = SA1100_CS3_PHYS + 0x01ffffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_NEPONSET_SMC9196,
.end = IRQ_NEPONSET_SMC9196,
.flags = IORESOURCE_IRQ,
},
[2] = {
.name = "smc91x-attrib",
.start = SA1100_CS3_PHYS + 0x02000000,
.end = SA1100_CS3_PHYS + 0x03ffffff,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device smc91x_device = {
.res = sa1111_resources,
.num_res = ARRAY_SIZE(sa1111_resources),
.data = &sa1111_info,
.size_data = sizeof(sa1111_info),
.dma_mask = 0xffffffffUL,
};
struct resource smc91x_resources[] = {
DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS,
0x02000000, "smc91x-regs"),
DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
0x02000000, "smc91x-attrib"),
{ .flags = IORESOURCE_IRQ },
};
struct platform_device_info smc91x_devinfo = {
.parent = &dev->dev,
.name = "smc91x",
.id = 0,
.num_resources = ARRAY_SIZE(smc91x_resources),
.resource = smc91x_resources,
};
.res = smc91x_resources,
.num_res = ARRAY_SIZE(smc91x_resources),
};
int ret, irq;
if (nep_base)
return -EBUSY;
irq = ret = platform_get_irq(dev, 0);
if (ret < 0)
goto err_alloc;
nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2);
if (!nep_res || !smc91x_res || !sa1111_res) {
ret = -ENXIO;
goto err_alloc;
}
static struct platform_device *devices[] __initdata = {
&neponset_device,
&sa1111_device,
&smc91x_device,
};
d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d) {
ret = -ENOMEM;
goto err_alloc;
}
extern void sa1110_mb_disable(void);
d->base = ioremap(nep_res->start, SZ_4K);
if (!d->base) {
ret = -ENOMEM;
goto err_ioremap;
}
static int __init neponset_init(void)
{
platform_driver_register(&neponset_device_driver);
if (readb_relaxed(d->base + WHOAMI) != 0x11) {
dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
readb_relaxed(d->base + WHOAMI));
ret = -ENODEV;
goto err_id;
}
/*
* The Neponset is only present on the Assabet machine type.
*/
if (!machine_is_assabet())
return -ENODEV;
ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1);
if (ret <= 0) {
dev_err(&dev->dev, "unable to allocate %u irqs: %d\n",
NEP_IRQ_NR, ret);
if (ret == 0)
ret = -ENOMEM;
goto err_irq_alloc;
}
d->irq_base = ret;
irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip,
handle_simple_irq);
set_irq_flags(d->irq_base + NEP_IRQ_SMC91X, IRQF_VALID | IRQF_PROBE);
irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip,
handle_simple_irq);
set_irq_flags(d->irq_base + NEP_IRQ_USAR, IRQF_VALID | IRQF_PROBE);
irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip);
irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
irq_set_handler_data(irq, d);
irq_set_chained_handler(irq, neponset_irq_handler);
/*
* Ensure that the memory bus request/grant signals are setup,
* and the grant is held in its inactive state, whether or not
* we actually have a Neponset attached.
* We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
* something on the Neponset activates this IRQ on sleep (eth?)
*/
#if 0
enable_irq_wake(irq);
#endif
dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
nep_base = d->base;
sa1100_register_uart_fns(&neponset_port_fns);
/* Ensure that the memory bus request/grant signals are setup */
sa1110_mb_disable();
if (!machine_has_neponset()) {
printk(KERN_DEBUG "Neponset expansion board not present\n");
return -ENODEV;
}
/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0);
if (WHOAMI != 0x11) {
printk(KERN_WARNING "Neponset board detected, but "
"wrong ID: %02x\n", WHOAMI);
return -ENODEV;
}
sa1111_resources[0].parent = sa1111_res;
sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111;
sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111;
d->sa1111 = platform_device_register_full(&sa1111_devinfo);
smc91x_resources[0].parent = smc91x_res;
smc91x_resources[1].parent = smc91x_res;
smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X;
smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X;
d->smc91x = platform_device_register_full(&smc91x_devinfo);
platform_set_drvdata(dev, d);
return platform_add_devices(devices, ARRAY_SIZE(devices));
return 0;
err_irq_alloc:
err_id:
iounmap(d->base);
err_ioremap:
kfree(d);
err_alloc:
return ret;
}
subsys_initcall(neponset_init);
static int __devexit neponset_remove(struct platform_device *dev)
{
struct neponset_drvdata *d = platform_get_drvdata(dev);
int irq = platform_get_irq(dev, 0);
if (!IS_ERR(d->sa1111))
platform_device_unregister(d->sa1111);
if (!IS_ERR(d->smc91x))
platform_device_unregister(d->smc91x);
irq_set_chained_handler(irq, NULL);
irq_free_descs(d->irq_base, NEP_IRQ_NR);
nep_base = NULL;
iounmap(d->base);
kfree(d);
static struct map_desc neponset_io_desc[] __initdata = {
{ /* System Registers */
.virtual = 0xf3000000,
.pfn = __phys_to_pfn(0x10000000),
.length = SZ_1M,
.type = MT_DEVICE
}, { /* SA-1111 */
.virtual = 0xf4000000,
.pfn = __phys_to_pfn(0x40000000),
.length = SZ_1M,
.type = MT_DEVICE
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int neponset_suspend(struct device *dev)
{
struct neponset_drvdata *d = dev_get_drvdata(dev);
d->ncr0 = readb_relaxed(d->base + NCR_0);
d->mdm_ctl_0 = readb_relaxed(d->base + MDM_CTL_0);
return 0;
}
static int neponset_resume(struct device *dev)
{
struct neponset_drvdata *d = dev_get_drvdata(dev);
writeb_relaxed(d->ncr0, d->base + NCR_0);
writeb_relaxed(d->mdm_ctl_0, d->base + MDM_CTL_0);
return 0;
}
static const struct dev_pm_ops neponset_pm_ops = {
.suspend_noirq = neponset_suspend,
.resume_noirq = neponset_resume,
.freeze_noirq = neponset_suspend,
.restore_noirq = neponset_resume,
};
#define PM_OPS &neponset_pm_ops
#else
#define PM_OPS NULL
#endif
static struct platform_driver neponset_device_driver = {
.probe = neponset_probe,
.remove = __devexit_p(neponset_remove),
.driver = {
.name = "neponset",
.owner = THIS_MODULE,
.pm = PM_OPS,
},
};
void __init neponset_map_io(void)
static int __init neponset_init(void)
{
iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc));
return platform_driver_register(&neponset_device_driver);
}
subsys_initcall(neponset_init);
......@@ -135,12 +135,8 @@ struct pci_bus * __init pci_nanoengine_scan_bus(int nr, struct pci_sys_data *sys
&sys->resources);
}
static struct resource pci_io_ports = {
.name = "PCI IO",
.start = 0x400,
.end = 0x7FF,
.flags = IORESOURCE_IO,
};
static struct resource pci_io_ports =
DEFINE_RES_IO_NAMED(0x400, 0x400, "PCI IO");
static struct resource pci_non_prefetchable_memory = {
.name = "PCI non-prefetchable",
......
......@@ -37,17 +37,9 @@
#define IRQ_GPIO_ETH0_IRQ IRQ_GPIO21
static struct resource smc91x_resources[] = {
[0] = {
.start = PLEB_ETH0_P,
.end = PLEB_ETH0_P | 0x03ffffff,
.flags = IORESOURCE_MEM,
},
[0] = DEFINE_RES_MEM(PLEB_ETH0_P, 0x04000000),
#if 0 /* Autoprobe instead, to get rising/falling edge characteristic right */
[1] = {
.start = IRQ_GPIO_ETH0_IRQ,
.end = IRQ_GPIO_ETH0_IRQ,
.flags = IORESOURCE_IRQ,
},
[1] = DEFINE_RES_IRQ(IRQ_GPIO_ETH0_IRQ),
#endif
};
......@@ -70,16 +62,8 @@ static struct platform_device *devices[] __initdata = {
* the two SA1100 lowest chip select outputs.
*/
static struct resource pleb_flash_resources[] = {
[0] = {
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_8M - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = SA1100_CS1_PHYS,
.end = SA1100_CS1_PHYS + SZ_8M - 1,
.flags = IORESOURCE_MEM,
}
[0] = DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_8M),
[1] = DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_8M),
};
......@@ -147,6 +131,7 @@ static void __init pleb_map_io(void)
MACHINE_START(PLEB, "PLEB")
.map_io = pleb_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = pleb_init,
......
......@@ -9,6 +9,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <video/sa1100fb.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
......@@ -19,6 +21,7 @@
#include <asm/mach/serial_sa1100.h>
#include <mach/mcp.h>
#include <mach/shannon.h>
#include <mach/irqs.h>
#include "generic.h"
......@@ -46,19 +49,32 @@ static struct flash_platform_data shannon_flash_data = {
.nr_parts = ARRAY_SIZE(shannon_partitions),
};
static struct resource shannon_flash_resource = {
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_4M - 1,
.flags = IORESOURCE_MEM,
};
static struct resource shannon_flash_resource =
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_4M);
static struct mcp_plat_data shannon_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
};
static struct sa1100fb_mach_info shannon_lcd_info = {
.pixclock = 152500, .bpp = 8,
.xres = 640, .yres = 480,
.hsync_len = 4, .vsync_len = 3,
.left_margin = 2, .upper_margin = 0,
.right_margin = 1, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
.lccr3 = LCCR3_ACBsDiv(512),
};
static void __init shannon_init(void)
{
sa11x0_ppc_configure_mcp();
sa11x0_register_lcd(&shannon_lcd_info);
sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
sa11x0_register_mcp(&shannon_mcp_data);
}
......@@ -84,6 +100,7 @@ static void __init shannon_map_io(void)
MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
.atag_offset = 0x100,
.map_io = shannon_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = shannon_init,
......
......@@ -10,12 +10,12 @@
#include <linux/string.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <asm/setup.h>
......@@ -26,6 +26,7 @@
#include <asm/mach/serial_sa1100.h>
#include <mach/mcp.h>
#include <mach/simpad.h>
#include <mach/irqs.h>
#include <linux/serial_core.h>
#include <linux/ioport.h>
......@@ -176,21 +177,18 @@ static struct flash_platform_data simpad_flash_data = {
static struct resource simpad_flash_resources [] = {
{
.start = SA1100_CS0_PHYS,
.end = SA1100_CS0_PHYS + SZ_16M -1,
.flags = IORESOURCE_MEM,
}, {
.start = SA1100_CS1_PHYS,
.end = SA1100_CS1_PHYS + SZ_16M -1,
.flags = IORESOURCE_MEM,
}
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_16M),
DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_16M),
};
static struct ucb1x00_plat_data simpad_ucb1x00_data = {
.gpio_base = SIMPAD_UCB1X00_GPIO_BASE,
};
static struct mcp_plat_data simpad_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.gpio_base = SIMPAD_UCB1X00_GPIO_BASE,
.codec_pdata = &simpad_ucb1x00_data,
};
......@@ -376,6 +374,7 @@ static int __init simpad_init(void)
pm_power_off = simpad_power_off;
sa11x0_ppc_configure_mcp();
sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
ARRAY_SIZE(simpad_flash_resources));
sa11x0_register_mcp(&simpad_mcp_data);
......@@ -394,6 +393,7 @@ MACHINE_START(SIMPAD, "Simpad")
/* Maintainer: Holger Freyther */
.atag_offset = 0x100,
.map_io = simpad_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.restart = sa11x0_restart,
......
......@@ -26,27 +26,36 @@
*
* Causes sa11x0 to enter sleep state
*
* Must be aligned to a cacheline.
*/
.balign 32
ENTRY(sa1100_finish_suspend)
@ disable clock switching
mcr p15, 0, r1, c15, c2, 2
ldr r6, =MDREFR
ldr r4, [r6]
orr r4, r4, #MDREFR_K1DB2
ldr r5, =PPCR
@ Pre-load __udelay into the I-cache
mov r0, #1
bl __udelay
mov r0, r0
@ The following must all exist in a single cache line to
@ avoid accessing memory until this sequence is complete,
@ otherwise we occasionally hang.
@ Adjust memory timing before lowering CPU clock
@ Clock speed adjustment without changing memory timing makes
@ CPU hang in some cases
ldr r0, =MDREFR
ldr r1, [r0]
orr r1, r1, #MDREFR_K1DB2
str r1, [r0]
str r4, [r6]
@ delay 90us and set CPU PLL to lowest speed
@ fixes resume problem on high speed SA1110
mov r0, #90
bl __udelay
ldr r0, =PPCR
mov r1, #0
str r1, [r0]
str r1, [r5]
mov r0, #90
bl __udelay
......@@ -85,12 +94,10 @@ ENTRY(sa1100_finish_suspend)
bic r5, r5, #FMsk(MSC_RT)
bic r5, r5, #FMsk(MSC_RT)<<16
ldr r6, =MDREFR
ldr r7, [r6]
bic r7, r7, #0x0000FF00
bic r7, r7, #0x000000F0
orr r8, r7, #MDREFR_SLFRSH
bic r7, r7, #0x0000FF00
bic r7, r7, #0x000000F0
orr r8, r7, #MDREFR_SLFRSH
ldr r9, =MDCNFG
ldr r10, [r9]
......
......@@ -19,8 +19,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <asm/hardware/ssp.h>
#define TIMEOUT 100000
......
......@@ -18,6 +18,7 @@
#include <asm/mach/time.h>
#include <asm/sched_clock.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
static u32 notrace sa1100_read_sched_clock(void)
{
......
......@@ -252,6 +252,15 @@ config EP93XX_DMA
help
Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller.
config DMA_SA11X0
tristate "SA-11x0 DMA support"
depends on ARCH_SA1100
select DMA_ENGINE
help
Support the DMA engine found on Intel StrongARM SA-1100 and
SA-1110 SoCs. This DMA engine can only be used with on-chip
devices.
config DMA_ENGINE
bool
......
......@@ -27,3 +27,4 @@ obj-$(CONFIG_PL330_DMA) += pl330.o
obj-$(CONFIG_PCH_DMA) += pch_dma.o
obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
/*
* SA11x0 DMAengine support
*
* Copyright (C) 2012 Russell King
* Derived in part from arch/arm/mach-sa1100/dma.c,
* Copyright (C) 2000, 2001 by Nicolas Pitre
*
* 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.
*/
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sa11x0-dma.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#define NR_PHY_CHAN 6
#define DMA_ALIGN 3
#define DMA_MAX_SIZE 0x1fff
#define DMA_CHUNK_SIZE 0x1000
#define DMA_DDAR 0x00
#define DMA_DCSR_S 0x04
#define DMA_DCSR_C 0x08
#define DMA_DCSR_R 0x0c
#define DMA_DBSA 0x10
#define DMA_DBTA 0x14
#define DMA_DBSB 0x18
#define DMA_DBTB 0x1c
#define DMA_SIZE 0x20
#define DCSR_RUN (1 << 0)
#define DCSR_IE (1 << 1)
#define DCSR_ERROR (1 << 2)
#define DCSR_DONEA (1 << 3)
#define DCSR_STRTA (1 << 4)
#define DCSR_DONEB (1 << 5)
#define DCSR_STRTB (1 << 6)
#define DCSR_BIU (1 << 7)
#define DDAR_RW (1 << 0) /* 0 = W, 1 = R */
#define DDAR_E (1 << 1) /* 0 = LE, 1 = BE */
#define DDAR_BS (1 << 2) /* 0 = BS4, 1 = BS8 */
#define DDAR_DW (1 << 3) /* 0 = 8b, 1 = 16b */
#define DDAR_Ser0UDCTr (0x0 << 4)
#define DDAR_Ser0UDCRc (0x1 << 4)
#define DDAR_Ser1SDLCTr (0x2 << 4)
#define DDAR_Ser1SDLCRc (0x3 << 4)
#define DDAR_Ser1UARTTr (0x4 << 4)
#define DDAR_Ser1UARTRc (0x5 << 4)
#define DDAR_Ser2ICPTr (0x6 << 4)
#define DDAR_Ser2ICPRc (0x7 << 4)
#define DDAR_Ser3UARTTr (0x8 << 4)
#define DDAR_Ser3UARTRc (0x9 << 4)
#define DDAR_Ser4MCP0Tr (0xa << 4)
#define DDAR_Ser4MCP0Rc (0xb << 4)
#define DDAR_Ser4MCP1Tr (0xc << 4)
#define DDAR_Ser4MCP1Rc (0xd << 4)
#define DDAR_Ser4SSPTr (0xe << 4)
#define DDAR_Ser4SSPRc (0xf << 4)
struct sa11x0_dma_sg {
u32 addr;
u32 len;
};
struct sa11x0_dma_desc {
struct dma_async_tx_descriptor tx;
u32 ddar;
size_t size;
/* maybe protected by c->lock */
struct list_head node;
unsigned sglen;
struct sa11x0_dma_sg sg[0];
};
struct sa11x0_dma_phy;
struct sa11x0_dma_chan {
struct dma_chan chan;
spinlock_t lock;
dma_cookie_t lc;
/* protected by c->lock */
struct sa11x0_dma_phy *phy;
enum dma_status status;
struct list_head desc_submitted;
struct list_head desc_issued;
/* protected by d->lock */
struct list_head node;
u32 ddar;
const char *name;
};
struct sa11x0_dma_phy {
void __iomem *base;
struct sa11x0_dma_dev *dev;
unsigned num;
struct sa11x0_dma_chan *vchan;
/* Protected by c->lock */
unsigned sg_load;
struct sa11x0_dma_desc *txd_load;
unsigned sg_done;
struct sa11x0_dma_desc *txd_done;
#ifdef CONFIG_PM_SLEEP
u32 dbs[2];
u32 dbt[2];
u32 dcsr;
#endif
};
struct sa11x0_dma_dev {
struct dma_device slave;
void __iomem *base;
spinlock_t lock;
struct tasklet_struct task;
struct list_head chan_pending;
struct list_head desc_complete;
struct sa11x0_dma_phy phy[NR_PHY_CHAN];
};
static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan)
{
return container_of(chan, struct sa11x0_dma_chan, chan);
}
static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
{
return container_of(dmadev, struct sa11x0_dma_dev, slave);
}
static struct sa11x0_dma_desc *to_sa11x0_dma_tx(struct dma_async_tx_descriptor *tx)
{
return container_of(tx, struct sa11x0_dma_desc, tx);
}
static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c)
{
if (list_empty(&c->desc_issued))
return NULL;
return list_first_entry(&c->desc_issued, struct sa11x0_dma_desc, node);
}
static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd)
{
list_del(&txd->node);
p->txd_load = txd;
p->sg_load = 0;
dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n",
p->num, txd, txd->tx.cookie, txd->ddar);
}
static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p,
struct sa11x0_dma_chan *c)
{
struct sa11x0_dma_desc *txd = p->txd_load;
struct sa11x0_dma_sg *sg;
void __iomem *base = p->base;
unsigned dbsx, dbtx;
u32 dcsr;
if (!txd)
return;
dcsr = readl_relaxed(base + DMA_DCSR_R);
/* Don't try to load the next transfer if both buffers are started */
if ((dcsr & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB))
return;
if (p->sg_load == txd->sglen) {
struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c);
/*
* We have reached the end of the current descriptor.
* Peek at the next descriptor, and if compatible with
* the current, start processing it.
*/
if (txn && txn->ddar == txd->ddar) {
txd = txn;
sa11x0_dma_start_desc(p, txn);
} else {
p->txd_load = NULL;
return;
}
}
sg = &txd->sg[p->sg_load++];
/* Select buffer to load according to channel status */
if (((dcsr & (DCSR_BIU | DCSR_STRTB)) == (DCSR_BIU | DCSR_STRTB)) ||
((dcsr & (DCSR_BIU | DCSR_STRTA)) == 0)) {
dbsx = DMA_DBSA;
dbtx = DMA_DBTA;
dcsr = DCSR_STRTA | DCSR_IE | DCSR_RUN;
} else {
dbsx = DMA_DBSB;
dbtx = DMA_DBTB;
dcsr = DCSR_STRTB | DCSR_IE | DCSR_RUN;
}
writel_relaxed(sg->addr, base + dbsx);
writel_relaxed(sg->len, base + dbtx);
writel(dcsr, base + DMA_DCSR_S);
dev_dbg(p->dev->slave.dev, "pchan %u: load: DCSR:%02x DBS%c:%08x DBT%c:%08x\n",
p->num, dcsr,
'A' + (dbsx == DMA_DBSB), sg->addr,
'A' + (dbtx == DMA_DBTB), sg->len);
}
static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p,
struct sa11x0_dma_chan *c)
{
struct sa11x0_dma_desc *txd = p->txd_done;
if (++p->sg_done == txd->sglen) {
struct sa11x0_dma_dev *d = p->dev;
dev_vdbg(d->slave.dev, "pchan %u: txd %p[%x]: completed\n",
p->num, p->txd_done, p->txd_done->tx.cookie);
c->lc = txd->tx.cookie;
spin_lock(&d->lock);
list_add_tail(&txd->node, &d->desc_complete);
spin_unlock(&d->lock);
p->sg_done = 0;
p->txd_done = p->txd_load;
tasklet_schedule(&d->task);
}
sa11x0_dma_start_sg(p, c);
}
static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
{
struct sa11x0_dma_phy *p = dev_id;
struct sa11x0_dma_dev *d = p->dev;
struct sa11x0_dma_chan *c;
u32 dcsr;
dcsr = readl_relaxed(p->base + DMA_DCSR_R);
if (!(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB)))
return IRQ_NONE;
/* Clear reported status bits */
writel_relaxed(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB),
p->base + DMA_DCSR_C);
dev_dbg(d->slave.dev, "pchan %u: irq: DCSR:%02x\n", p->num, dcsr);
if (dcsr & DCSR_ERROR) {
dev_err(d->slave.dev, "pchan %u: error. DCSR:%02x DDAR:%08x DBSA:%08x DBTA:%08x DBSB:%08x DBTB:%08x\n",
p->num, dcsr,
readl_relaxed(p->base + DMA_DDAR),
readl_relaxed(p->base + DMA_DBSA),
readl_relaxed(p->base + DMA_DBTA),
readl_relaxed(p->base + DMA_DBSB),
readl_relaxed(p->base + DMA_DBTB));
}
c = p->vchan;
if (c) {
unsigned long flags;
spin_lock_irqsave(&c->lock, flags);
/*
* Now that we're holding the lock, check that the vchan
* really is associated with this pchan before touching the
* hardware. This should always succeed, because we won't
* change p->vchan or c->phy while the channel is actively
* transferring.
*/
if (c->phy == p) {
if (dcsr & DCSR_DONEA)
sa11x0_dma_complete(p, c);
if (dcsr & DCSR_DONEB)
sa11x0_dma_complete(p, c);
}
spin_unlock_irqrestore(&c->lock, flags);
}
return IRQ_HANDLED;
}
static void sa11x0_dma_start_txd(struct sa11x0_dma_chan *c)
{
struct sa11x0_dma_desc *txd = sa11x0_dma_next_desc(c);
/* If the issued list is empty, we have no further txds to process */
if (txd) {
struct sa11x0_dma_phy *p = c->phy;
sa11x0_dma_start_desc(p, txd);
p->txd_done = txd;
p->sg_done = 0;
/* The channel should not have any transfers started */
WARN_ON(readl_relaxed(p->base + DMA_DCSR_R) &
(DCSR_STRTA | DCSR_STRTB));
/* Clear the run and start bits before changing DDAR */
writel_relaxed(DCSR_RUN | DCSR_STRTA | DCSR_STRTB,
p->base + DMA_DCSR_C);
writel_relaxed(txd->ddar, p->base + DMA_DDAR);
/* Try to start both buffers */
sa11x0_dma_start_sg(p, c);
sa11x0_dma_start_sg(p, c);
}
}
static void sa11x0_dma_tasklet(unsigned long arg)
{
struct sa11x0_dma_dev *d = (struct sa11x0_dma_dev *)arg;
struct sa11x0_dma_phy *p;
struct sa11x0_dma_chan *c;
struct sa11x0_dma_desc *txd, *txn;
LIST_HEAD(head);
unsigned pch, pch_alloc = 0;
dev_dbg(d->slave.dev, "tasklet enter\n");
/* Get the completed tx descriptors */
spin_lock_irq(&d->lock);
list_splice_init(&d->desc_complete, &head);
spin_unlock_irq(&d->lock);
list_for_each_entry(txd, &head, node) {
c = to_sa11x0_dma_chan(txd->tx.chan);
dev_dbg(d->slave.dev, "vchan %p: txd %p[%x] completed\n",
c, txd, txd->tx.cookie);
spin_lock_irq(&c->lock);
p = c->phy;
if (p) {
if (!p->txd_done)
sa11x0_dma_start_txd(c);
if (!p->txd_done) {
/* No current txd associated with this channel */
dev_dbg(d->slave.dev, "pchan %u: free\n", p->num);
/* Mark this channel free */
c->phy = NULL;
p->vchan = NULL;
}
}
spin_unlock_irq(&c->lock);
}
spin_lock_irq(&d->lock);
for (pch = 0; pch < NR_PHY_CHAN; pch++) {
p = &d->phy[pch];
if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
c = list_first_entry(&d->chan_pending,
struct sa11x0_dma_chan, node);
list_del_init(&c->node);
pch_alloc |= 1 << pch;
/* Mark this channel allocated */
p->vchan = c;
dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, c);
}
}
spin_unlock_irq(&d->lock);
for (pch = 0; pch < NR_PHY_CHAN; pch++) {
if (pch_alloc & (1 << pch)) {
p = &d->phy[pch];
c = p->vchan;
spin_lock_irq(&c->lock);
c->phy = p;
sa11x0_dma_start_txd(c);
spin_unlock_irq(&c->lock);
}
}
/* Now free the completed tx descriptor, and call their callbacks */
list_for_each_entry_safe(txd, txn, &head, node) {
dma_async_tx_callback callback = txd->tx.callback;
void *callback_param = txd->tx.callback_param;
dev_dbg(d->slave.dev, "txd %p[%x]: callback and free\n",
txd, txd->tx.cookie);
kfree(txd);
if (callback)
callback(callback_param);
}
dev_dbg(d->slave.dev, "tasklet exit\n");
}
static void sa11x0_dma_desc_free(struct sa11x0_dma_dev *d, struct list_head *head)
{
struct sa11x0_dma_desc *txd, *txn;
list_for_each_entry_safe(txd, txn, head, node) {
dev_dbg(d->slave.dev, "txd %p: freeing\n", txd);
kfree(txd);
}
}
static int sa11x0_dma_alloc_chan_resources(struct dma_chan *chan)
{
return 0;
}
static void sa11x0_dma_free_chan_resources(struct dma_chan *chan)
{
struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
unsigned long flags;
LIST_HEAD(head);
spin_lock_irqsave(&c->lock, flags);
spin_lock(&d->lock);
list_del_init(&c->node);
spin_unlock(&d->lock);
list_splice_tail_init(&c->desc_submitted, &head);
list_splice_tail_init(&c->desc_issued, &head);
spin_unlock_irqrestore(&c->lock, flags);
sa11x0_dma_desc_free(d, &head);
}
static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p)
{
unsigned reg;
u32 dcsr;
dcsr = readl_relaxed(p->base + DMA_DCSR_R);
if ((dcsr & (DCSR_BIU | DCSR_STRTA)) == DCSR_STRTA ||
(dcsr & (DCSR_BIU | DCSR_STRTB)) == DCSR_BIU)
reg = DMA_DBSA;
else
reg = DMA_DBSB;
return readl_relaxed(p->base + reg);
}
static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
dma_cookie_t cookie, struct dma_tx_state *state)
{
struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
struct sa11x0_dma_phy *p;
struct sa11x0_dma_desc *txd;
dma_cookie_t last_used, last_complete;
unsigned long flags;
enum dma_status ret;
size_t bytes = 0;
last_used = c->chan.cookie;
last_complete = c->lc;
ret = dma_async_is_complete(cookie, last_complete, last_used);
if (ret == DMA_SUCCESS) {
dma_set_tx_state(state, last_complete, last_used, 0);
return ret;
}
spin_lock_irqsave(&c->lock, flags);
p = c->phy;
ret = c->status;
if (p) {
dma_addr_t addr = sa11x0_dma_pos(p);
dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
txd = p->txd_done;
if (txd) {
unsigned i;
for (i = 0; i < txd->sglen; i++) {
dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
i, txd->sg[i].addr, txd->sg[i].len);
if (addr >= txd->sg[i].addr &&
addr < txd->sg[i].addr + txd->sg[i].len) {
unsigned len;
len = txd->sg[i].len -
(addr - txd->sg[i].addr);
dev_vdbg(d->slave.dev, "tx_status: [%u] +%x\n",
i, len);
bytes += len;
i++;
break;
}
}
for (; i < txd->sglen; i++) {
dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x ++\n",
i, txd->sg[i].addr, txd->sg[i].len);
bytes += txd->sg[i].len;
}
}
if (txd != p->txd_load && p->txd_load)
bytes += p->txd_load->size;
}
list_for_each_entry(txd, &c->desc_issued, node) {
bytes += txd->size;
}
spin_unlock_irqrestore(&c->lock, flags);
dma_set_tx_state(state, last_complete, last_used, bytes);
dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes);
return ret;
}
/*
* Move pending txds to the issued list, and re-init pending list.
* If not already pending, add this channel to the list of pending
* channels and trigger the tasklet to run.
*/
static void sa11x0_dma_issue_pending(struct dma_chan *chan)
{
struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
unsigned long flags;
spin_lock_irqsave(&c->lock, flags);
list_splice_tail_init(&c->desc_submitted, &c->desc_issued);
if (!list_empty(&c->desc_issued)) {
spin_lock(&d->lock);
if (!c->phy && list_empty(&c->node)) {
list_add_tail(&c->node, &d->chan_pending);
tasklet_schedule(&d->task);
dev_dbg(d->slave.dev, "vchan %p: issued\n", c);
}
spin_unlock(&d->lock);
} else
dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", c);
spin_unlock_irqrestore(&c->lock, flags);
}
static dma_cookie_t sa11x0_dma_tx_submit(struct dma_async_tx_descriptor *tx)
{
struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(tx->chan);
struct sa11x0_dma_desc *txd = to_sa11x0_dma_tx(tx);
unsigned long flags;
spin_lock_irqsave(&c->lock, flags);
c->chan.cookie += 1;
if (c->chan.cookie < 0)
c->chan.cookie = 1;
txd->tx.cookie = c->chan.cookie;
list_add_tail(&txd->node, &c->desc_submitted);
spin_unlock_irqrestore(&c->lock, flags);
dev_dbg(tx->chan->device->dev, "vchan %p: txd %p[%x]: submitted\n",
c, txd, txd->tx.cookie);
return txd->tx.cookie;
}
static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen,
enum dma_transfer_direction dir, unsigned long flags)
{
struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
struct sa11x0_dma_desc *txd;
struct scatterlist *sgent;
unsigned i, j = sglen;
size_t size = 0;
/* SA11x0 channels can only operate in their native direction */
if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
c, c->ddar, dir);
return NULL;
}
/* Do not allow zero-sized txds */
if (sglen == 0)
return NULL;
for_each_sg(sg, sgent, sglen, i) {
dma_addr_t addr = sg_dma_address(sgent);
unsigned int len = sg_dma_len(sgent);
if (len > DMA_MAX_SIZE)
j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
if (addr & DMA_ALIGN) {
dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n",
c, addr);
return NULL;
}
}
txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC);
if (!txd) {
dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", c);
return NULL;
}
j = 0;
for_each_sg(sg, sgent, sglen, i) {
dma_addr_t addr = sg_dma_address(sgent);
unsigned len = sg_dma_len(sgent);
size += len;
do {
unsigned tlen = len;
/*
* Check whether the transfer will fit. If not, try
* to split the transfer up such that we end up with
* equal chunks - but make sure that we preserve the
* alignment. This avoids small segments.
*/
if (tlen > DMA_MAX_SIZE) {
unsigned mult = DIV_ROUND_UP(tlen,
DMA_MAX_SIZE & ~DMA_ALIGN);
tlen = (tlen / mult) & ~DMA_ALIGN;
}
txd->sg[j].addr = addr;
txd->sg[j].len = tlen;
addr += tlen;
len -= tlen;
j++;
} while (len);
}
dma_async_tx_descriptor_init(&txd->tx, &c->chan);
txd->tx.flags = flags;
txd->tx.tx_submit = sa11x0_dma_tx_submit;
txd->ddar = c->ddar;
txd->size = size;
txd->sglen = j;
dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n",
c, txd, txd->size, txd->sglen);
return &txd->tx;
}
static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg)
{
u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW);
dma_addr_t addr;
enum dma_slave_buswidth width;
u32 maxburst;
if (ddar & DDAR_RW) {
addr = cfg->src_addr;
width = cfg->src_addr_width;
maxburst = cfg->src_maxburst;
} else {
addr = cfg->dst_addr;
width = cfg->dst_addr_width;
maxburst = cfg->dst_maxburst;
}
if ((width != DMA_SLAVE_BUSWIDTH_1_BYTE &&
width != DMA_SLAVE_BUSWIDTH_2_BYTES) ||
(maxburst != 4 && maxburst != 8))
return -EINVAL;
if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
ddar |= DDAR_DW;
if (maxburst == 8)
ddar |= DDAR_BS;
dev_dbg(c->chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
c, addr, width, maxburst);
c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
return 0;
}
static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
unsigned long arg)
{
struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
struct sa11x0_dma_phy *p;
LIST_HEAD(head);
unsigned long flags;
int ret;
switch (cmd) {
case DMA_SLAVE_CONFIG:
return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg);
case DMA_TERMINATE_ALL:
dev_dbg(d->slave.dev, "vchan %p: terminate all\n", c);
/* Clear the tx descriptor lists */
spin_lock_irqsave(&c->lock, flags);
list_splice_tail_init(&c->desc_submitted, &head);
list_splice_tail_init(&c->desc_issued, &head);
p = c->phy;
if (p) {
struct sa11x0_dma_desc *txd, *txn;
dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
/* vchan is assigned to a pchan - stop the channel */
writel(DCSR_RUN | DCSR_IE |
DCSR_STRTA | DCSR_DONEA |
DCSR_STRTB | DCSR_DONEB,
p->base + DMA_DCSR_C);
list_for_each_entry_safe(txd, txn, &d->desc_complete, node)
if (txd->tx.chan == &c->chan)
list_move(&txd->node, &head);
if (p->txd_load) {
if (p->txd_load != p->txd_done)
list_add_tail(&p->txd_load->node, &head);
p->txd_load = NULL;
}
if (p->txd_done) {
list_add_tail(&p->txd_done->node, &head);
p->txd_done = NULL;
}
c->phy = NULL;
spin_lock(&d->lock);
p->vchan = NULL;
spin_unlock(&d->lock);
tasklet_schedule(&d->task);
}
spin_unlock_irqrestore(&c->lock, flags);
sa11x0_dma_desc_free(d, &head);
ret = 0;
break;
case DMA_PAUSE:
dev_dbg(d->slave.dev, "vchan %p: pause\n", c);
spin_lock_irqsave(&c->lock, flags);
if (c->status == DMA_IN_PROGRESS) {
c->status = DMA_PAUSED;
p = c->phy;
if (p) {
writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
} else {
spin_lock(&d->lock);
list_del_init(&c->node);
spin_unlock(&d->lock);
}
}
spin_unlock_irqrestore(&c->lock, flags);
ret = 0;
break;
case DMA_RESUME:
dev_dbg(d->slave.dev, "vchan %p: resume\n", c);
spin_lock_irqsave(&c->lock, flags);
if (c->status == DMA_PAUSED) {
c->status = DMA_IN_PROGRESS;
p = c->phy;
if (p) {
writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
} else if (!list_empty(&c->desc_issued)) {
spin_lock(&d->lock);
list_add_tail(&c->node, &d->chan_pending);
spin_unlock(&d->lock);
}
}
spin_unlock_irqrestore(&c->lock, flags);
ret = 0;
break;
default:
ret = -ENXIO;
break;
}
return ret;
}
struct sa11x0_dma_channel_desc {
u32 ddar;
const char *name;
};
#define CD(d1, d2) { .ddar = DDAR_##d1 | d2, .name = #d1 }
static const struct sa11x0_dma_channel_desc chan_desc[] = {
CD(Ser0UDCTr, 0),
CD(Ser0UDCRc, DDAR_RW),
CD(Ser1SDLCTr, 0),
CD(Ser1SDLCRc, DDAR_RW),
CD(Ser1UARTTr, 0),
CD(Ser1UARTRc, DDAR_RW),
CD(Ser2ICPTr, 0),
CD(Ser2ICPRc, DDAR_RW),
CD(Ser3UARTTr, 0),
CD(Ser3UARTRc, DDAR_RW),
CD(Ser4MCP0Tr, 0),
CD(Ser4MCP0Rc, DDAR_RW),
CD(Ser4MCP1Tr, 0),
CD(Ser4MCP1Rc, DDAR_RW),
CD(Ser4SSPTr, 0),
CD(Ser4SSPRc, DDAR_RW),
};
static int __devinit sa11x0_dma_init_dmadev(struct dma_device *dmadev,
struct device *dev)
{
unsigned i;
dmadev->chancnt = ARRAY_SIZE(chan_desc);
INIT_LIST_HEAD(&dmadev->channels);
dmadev->dev = dev;
dmadev->device_alloc_chan_resources = sa11x0_dma_alloc_chan_resources;
dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources;
dmadev->device_control = sa11x0_dma_control;
dmadev->device_tx_status = sa11x0_dma_tx_status;
dmadev->device_issue_pending = sa11x0_dma_issue_pending;
for (i = 0; i < dmadev->chancnt; i++) {
struct sa11x0_dma_chan *c;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c) {
dev_err(dev, "no memory for channel %u\n", i);
return -ENOMEM;
}
c->chan.device = dmadev;
c->status = DMA_IN_PROGRESS;
c->ddar = chan_desc[i].ddar;
c->name = chan_desc[i].name;
spin_lock_init(&c->lock);
INIT_LIST_HEAD(&c->desc_submitted);
INIT_LIST_HEAD(&c->desc_issued);
INIT_LIST_HEAD(&c->node);
list_add_tail(&c->chan.device_node, &dmadev->channels);
}
return dma_async_device_register(dmadev);
}
static int sa11x0_dma_request_irq(struct platform_device *pdev, int nr,
void *data)
{
int irq = platform_get_irq(pdev, nr);
if (irq <= 0)
return -ENXIO;
return request_irq(irq, sa11x0_dma_irq, 0, dev_name(&pdev->dev), data);
}
static void sa11x0_dma_free_irq(struct platform_device *pdev, int nr,
void *data)
{
int irq = platform_get_irq(pdev, nr);
if (irq > 0)
free_irq(irq, data);
}
static void sa11x0_dma_free_channels(struct dma_device *dmadev)
{
struct sa11x0_dma_chan *c, *cn;
list_for_each_entry_safe(c, cn, &dmadev->channels, chan.device_node) {
list_del(&c->chan.device_node);
kfree(c);
}
}
static int __devinit sa11x0_dma_probe(struct platform_device *pdev)
{
struct sa11x0_dma_dev *d;
struct resource *res;
unsigned i;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENXIO;
d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d) {
ret = -ENOMEM;
goto err_alloc;
}
spin_lock_init(&d->lock);
INIT_LIST_HEAD(&d->chan_pending);
INIT_LIST_HEAD(&d->desc_complete);
d->base = ioremap(res->start, resource_size(res));
if (!d->base) {
ret = -ENOMEM;
goto err_ioremap;
}
tasklet_init(&d->task, sa11x0_dma_tasklet, (unsigned long)d);
for (i = 0; i < NR_PHY_CHAN; i++) {
struct sa11x0_dma_phy *p = &d->phy[i];
p->dev = d;
p->num = i;
p->base = d->base + i * DMA_SIZE;
writel_relaxed(DCSR_RUN | DCSR_IE | DCSR_ERROR |
DCSR_DONEA | DCSR_STRTA | DCSR_DONEB | DCSR_STRTB,
p->base + DMA_DCSR_C);
writel_relaxed(0, p->base + DMA_DDAR);
ret = sa11x0_dma_request_irq(pdev, i, p);
if (ret) {
while (i) {
i--;
sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
}
goto err_irq;
}
}
dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
d->slave.device_prep_slave_sg = sa11x0_dma_prep_slave_sg;
ret = sa11x0_dma_init_dmadev(&d->slave, &pdev->dev);
if (ret) {
dev_warn(d->slave.dev, "failed to register slave async device: %d\n",
ret);
goto err_slave_reg;
}
platform_set_drvdata(pdev, d);
return 0;
err_slave_reg:
sa11x0_dma_free_channels(&d->slave);
for (i = 0; i < NR_PHY_CHAN; i++)
sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
err_irq:
tasklet_kill(&d->task);
iounmap(d->base);
err_ioremap:
kfree(d);
err_alloc:
return ret;
}
static int __devexit sa11x0_dma_remove(struct platform_device *pdev)
{
struct sa11x0_dma_dev *d = platform_get_drvdata(pdev);
unsigned pch;
dma_async_device_unregister(&d->slave);
sa11x0_dma_free_channels(&d->slave);
for (pch = 0; pch < NR_PHY_CHAN; pch++)
sa11x0_dma_free_irq(pdev, pch, &d->phy[pch]);
tasklet_kill(&d->task);
iounmap(d->base);
kfree(d);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int sa11x0_dma_suspend(struct device *dev)
{
struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
unsigned pch;
for (pch = 0; pch < NR_PHY_CHAN; pch++) {
struct sa11x0_dma_phy *p = &d->phy[pch];
u32 dcsr, saved_dcsr;
dcsr = saved_dcsr = readl_relaxed(p->base + DMA_DCSR_R);
if (dcsr & DCSR_RUN) {
writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
dcsr = readl_relaxed(p->base + DMA_DCSR_R);
}
saved_dcsr &= DCSR_RUN | DCSR_IE;
if (dcsr & DCSR_BIU) {
p->dbs[0] = readl_relaxed(p->base + DMA_DBSB);
p->dbt[0] = readl_relaxed(p->base + DMA_DBTB);
p->dbs[1] = readl_relaxed(p->base + DMA_DBSA);
p->dbt[1] = readl_relaxed(p->base + DMA_DBTA);
saved_dcsr |= (dcsr & DCSR_STRTA ? DCSR_STRTB : 0) |
(dcsr & DCSR_STRTB ? DCSR_STRTA : 0);
} else {
p->dbs[0] = readl_relaxed(p->base + DMA_DBSA);
p->dbt[0] = readl_relaxed(p->base + DMA_DBTA);
p->dbs[1] = readl_relaxed(p->base + DMA_DBSB);
p->dbt[1] = readl_relaxed(p->base + DMA_DBTB);
saved_dcsr |= dcsr & (DCSR_STRTA | DCSR_STRTB);
}
p->dcsr = saved_dcsr;
writel(DCSR_STRTA | DCSR_STRTB, p->base + DMA_DCSR_C);
}
return 0;
}
static int sa11x0_dma_resume(struct device *dev)
{
struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
unsigned pch;
for (pch = 0; pch < NR_PHY_CHAN; pch++) {
struct sa11x0_dma_phy *p = &d->phy[pch];
struct sa11x0_dma_desc *txd = NULL;
u32 dcsr = readl_relaxed(p->base + DMA_DCSR_R);
WARN_ON(dcsr & (DCSR_BIU | DCSR_STRTA | DCSR_STRTB | DCSR_RUN));
if (p->txd_done)
txd = p->txd_done;
else if (p->txd_load)
txd = p->txd_load;
if (!txd)
continue;
writel_relaxed(txd->ddar, p->base + DMA_DDAR);
writel_relaxed(p->dbs[0], p->base + DMA_DBSA);
writel_relaxed(p->dbt[0], p->base + DMA_DBTA);
writel_relaxed(p->dbs[1], p->base + DMA_DBSB);
writel_relaxed(p->dbt[1], p->base + DMA_DBTB);
writel_relaxed(p->dcsr, p->base + DMA_DCSR_S);
}
return 0;
}
#endif
static const struct dev_pm_ops sa11x0_dma_pm_ops = {
.suspend_noirq = sa11x0_dma_suspend,
.resume_noirq = sa11x0_dma_resume,
.freeze_noirq = sa11x0_dma_suspend,
.thaw_noirq = sa11x0_dma_resume,
.poweroff_noirq = sa11x0_dma_suspend,
.restore_noirq = sa11x0_dma_resume,
};
static struct platform_driver sa11x0_dma_driver = {
.driver = {
.name = "sa11x0-dma",
.owner = THIS_MODULE,
.pm = &sa11x0_dma_pm_ops,
},
.probe = sa11x0_dma_probe,
.remove = __devexit_p(sa11x0_dma_remove),
};
bool sa11x0_dma_filter_fn(struct dma_chan *chan, void *param)
{
if (chan->device->dev->driver == &sa11x0_dma_driver.driver) {
struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
const char *p = param;
return !strcmp(c->name, p);
}
return false;
}
EXPORT_SYMBOL(sa11x0_dma_filter_fn);
static int __init sa11x0_dma_init(void)
{
return platform_driver_register(&sa11x0_dma_driver);
}
subsys_initcall(sa11x0_dma_init);
static void __exit sa11x0_dma_exit(void)
{
platform_driver_unregister(&sa11x0_dma_driver);
}
module_exit(sa11x0_dma_exit);
MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("SA-11x0 DMA driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:sa11x0-dma");
......@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset)
{
......
......@@ -27,6 +27,7 @@
#include <mach/jornada720.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver");
......
......@@ -24,6 +24,26 @@
#include <asm/hardware/sa1111.h>
#define PS2CR 0x0000
#define PS2STAT 0x0004
#define PS2DATA 0x0008
#define PS2CLKDIV 0x000c
#define PS2PRECNT 0x0010
#define PS2CR_ENA 0x08
#define PS2CR_FKD 0x02
#define PS2CR_FKC 0x01
#define PS2STAT_STP 0x0100
#define PS2STAT_TXE 0x0080
#define PS2STAT_TXB 0x0040
#define PS2STAT_RXF 0x0020
#define PS2STAT_RXB 0x0010
#define PS2STAT_ENA 0x0008
#define PS2STAT_RXP 0x0004
#define PS2STAT_KBD 0x0002
#define PS2STAT_KBC 0x0001
struct ps2if {
struct serio *io;
struct sa1111_dev *dev;
......@@ -45,22 +65,22 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id)
struct ps2if *ps2if = dev_id;
unsigned int scancode, flag, status;
status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
status = sa1111_readl(ps2if->base + PS2STAT);
while (status & PS2STAT_RXF) {
if (status & PS2STAT_STP)
sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT);
sa1111_writel(PS2STAT_STP, ps2if->base + PS2STAT);
flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
(status & PS2STAT_RXP ? 0 : SERIO_PARITY);
scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff;
scancode = sa1111_readl(ps2if->base + PS2DATA) & 0xff;
if (hweight8(scancode) & 1)
flag ^= SERIO_PARITY;
serio_interrupt(ps2if->io, scancode, flag);
status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
status = sa1111_readl(ps2if->base + PS2STAT);
}
return IRQ_HANDLED;
......@@ -75,12 +95,12 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
unsigned int status;
spin_lock(&ps2if->lock);
status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
status = sa1111_readl(ps2if->base + PS2STAT);
if (ps2if->head == ps2if->tail) {
disable_irq_nosync(irq);
/* done */
} else if (status & PS2STAT_TXE) {
sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA);
sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA);
ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
}
spin_unlock(&ps2if->lock);
......@@ -103,8 +123,8 @@ static int ps2_write(struct serio *io, unsigned char val)
/*
* If the TX register is empty, we can go straight out.
*/
if (sa1111_readl(ps2if->base + SA1111_PS2STAT) & PS2STAT_TXE) {
sa1111_writel(val, ps2if->base + SA1111_PS2DATA);
if (sa1111_readl(ps2if->base + PS2STAT) & PS2STAT_TXE) {
sa1111_writel(val, ps2if->base + PS2DATA);
} else {
if (ps2if->head == ps2if->tail)
enable_irq(ps2if->dev->irq[1]);
......@@ -124,13 +144,16 @@ static int ps2_open(struct serio *io)
struct ps2if *ps2if = io->port_data;
int ret;
sa1111_enable_device(ps2if->dev);
ret = sa1111_enable_device(ps2if->dev);
if (ret)
return ret;
ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0,
SA1111_DRIVER_NAME(ps2if->dev), ps2if);
if (ret) {
printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
ps2if->dev->irq[0], ret);
sa1111_disable_device(ps2if->dev);
return ret;
}
......@@ -140,6 +163,7 @@ static int ps2_open(struct serio *io)
printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
ps2if->dev->irq[1], ret);
free_irq(ps2if->dev->irq[0], ps2if);
sa1111_disable_device(ps2if->dev);
return ret;
}
......@@ -147,7 +171,7 @@ static int ps2_open(struct serio *io)
enable_irq_wake(ps2if->dev->irq[0]);
sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR);
sa1111_writel(PS2CR_ENA, ps2if->base + PS2CR);
return 0;
}
......@@ -155,7 +179,7 @@ static void ps2_close(struct serio *io)
{
struct ps2if *ps2if = io->port_data;
sa1111_writel(0, ps2if->base + SA1111_PS2CR);
sa1111_writel(0, ps2if->base + PS2CR);
disable_irq_wake(ps2if->dev->irq[0]);
......@@ -175,7 +199,7 @@ static void __devinit ps2_clear_input(struct ps2if *ps2if)
int maxread = 100;
while (maxread--) {
if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff)
if ((sa1111_readl(ps2if->base + PS2DATA) & 0xff) == 0xff)
break;
}
}
......@@ -185,11 +209,11 @@ static unsigned int __devinit ps2_test_one(struct ps2if *ps2if,
{
unsigned int val;
sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR);
sa1111_writel(PS2CR_ENA | mask, ps2if->base + PS2CR);
udelay(2);
val = sa1111_readl(ps2if->base + SA1111_PS2STAT);
val = sa1111_readl(ps2if->base + PS2STAT);
return val & (PS2STAT_KBC | PS2STAT_KBD);
}
......@@ -220,7 +244,7 @@ static int __devinit ps2_test(struct ps2if *ps2if)
ret = -ENODEV;
}
sa1111_writel(0, ps2if->base + SA1111_PS2CR);
sa1111_writel(0, ps2if->base + PS2CR);
return ret;
}
......@@ -274,8 +298,8 @@ static int __devinit ps2_probe(struct sa1111_dev *dev)
sa1111_enable_device(ps2if->dev);
/* Incoming clock is 8MHz */
sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV);
sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT);
sa1111_writel(0, ps2if->base + PS2CLKDIV);
sa1111_writel(127, ps2if->base + PS2PRECNT);
/*
* Flush any pending input.
......@@ -330,6 +354,7 @@ static int __devexit ps2_remove(struct sa1111_dev *dev)
static struct sa1111_driver ps2_driver = {
.drv = {
.name = "sa1111-ps2",
.owner = THIS_MODULE,
},
.devid = SA1111_DEVID_PS2,
.probe = ps2_probe,
......
......@@ -22,6 +22,7 @@
#include <mach/hardware.h>
#include <mach/jornada720.h>
#include <mach/irqs.h>
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
......
......@@ -847,8 +847,9 @@ config MCP_SA11X0
# Chip drivers
config MCP_UCB1200
tristate "Support for UCB1200 / UCB1300"
depends on MCP
bool "Support for UCB1200 / UCB1300"
depends on MCP_SA11X0
select MCP
config MCP_UCB1200_TS
tristate "Touchscreen interface support"
......
......@@ -19,7 +19,6 @@
#include <linux/string.h>
#include <linux/mfd/mcp.h>
#include <mach/dma.h>
#include <asm/system.h>
......@@ -48,39 +47,11 @@ static int mcp_bus_remove(struct device *dev)
return 0;
}
static int mcp_bus_suspend(struct device *dev, pm_message_t state)
{
struct mcp *mcp = to_mcp(dev);
int ret = 0;
if (dev->driver) {
struct mcp_driver *drv = to_mcp_driver(dev->driver);
ret = drv->suspend(mcp, state);
}
return ret;
}
static int mcp_bus_resume(struct device *dev)
{
struct mcp *mcp = to_mcp(dev);
int ret = 0;
if (dev->driver) {
struct mcp_driver *drv = to_mcp_driver(dev->driver);
ret = drv->resume(mcp);
}
return ret;
}
static struct bus_type mcp_bus_type = {
.name = "mcp",
.match = mcp_bus_match,
.probe = mcp_bus_probe,
.remove = mcp_bus_remove,
.suspend = mcp_bus_suspend,
.resume = mcp_bus_resume,
};
/**
......@@ -208,6 +179,7 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
if (mcp) {
spin_lock_init(&mcp->lock);
device_initialize(&mcp->attached_device);
mcp->attached_device.parent = parent;
mcp->attached_device.bus = &mcp_bus_type;
mcp->attached_device.dma_mask = parent->dma_mask;
......@@ -217,18 +189,25 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
}
EXPORT_SYMBOL(mcp_host_alloc);
int mcp_host_register(struct mcp *mcp)
int mcp_host_add(struct mcp *mcp, void *pdata)
{
mcp->attached_device.platform_data = pdata;
dev_set_name(&mcp->attached_device, "mcp0");
return device_register(&mcp->attached_device);
return device_add(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_add);
void mcp_host_del(struct mcp *mcp)
{
device_del(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_register);
EXPORT_SYMBOL(mcp_host_del);
void mcp_host_unregister(struct mcp *mcp)
void mcp_host_free(struct mcp *mcp)
{
device_unregister(&mcp->attached_device);
put_device(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_unregister);
EXPORT_SYMBOL(mcp_host_free);
int mcp_driver_register(struct mcp_driver *mcpdrv)
{
......
......@@ -13,51 +13,61 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/mfd/mcp.h>
#include <mach/dma.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/system.h>
#include <mach/mcp.h>
#include <mach/assabet.h>
#define DRIVER_NAME "sa11x0-mcp"
struct mcp_sa11x0 {
void __iomem *base0;
void __iomem *base1;
u32 mccr0;
u32 mccr1;
};
/* Register offsets */
#define MCCR0(m) ((m)->base0 + 0x00)
#define MCDR0(m) ((m)->base0 + 0x08)
#define MCDR1(m) ((m)->base0 + 0x0c)
#define MCDR2(m) ((m)->base0 + 0x10)
#define MCSR(m) ((m)->base0 + 0x18)
#define MCCR1(m) ((m)->base1 + 0x00)
#define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp))
static void
mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
{
unsigned int mccr0;
struct mcp_sa11x0 *m = priv(mcp);
divisor /= 32;
mccr0 = Ser4MCCR0 & ~0x00007f00;
mccr0 |= divisor << 8;
Ser4MCCR0 = mccr0;
m->mccr0 &= ~0x00007f00;
m->mccr0 |= divisor << 8;
writel_relaxed(m->mccr0, MCCR0(m));
}
static void
mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
{
unsigned int mccr0;
struct mcp_sa11x0 *m = priv(mcp);
divisor /= 32;
mccr0 = Ser4MCCR0 & ~0x0000007f;
mccr0 |= divisor;
Ser4MCCR0 = mccr0;
m->mccr0 &= ~0x0000007f;
m->mccr0 |= divisor;
writel_relaxed(m->mccr0, MCCR0(m));
}
/*
......@@ -69,14 +79,15 @@ mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
static void
mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
{
struct mcp_sa11x0 *m = priv(mcp);
int ret = -ETIME;
int i;
Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m));
for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout);
if (Ser4MCSR & MCSR_CWC) {
if (readl_relaxed(MCSR(m)) & MCSR_CWC) {
ret = 0;
break;
}
......@@ -95,15 +106,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
static unsigned int
mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
{
struct mcp_sa11x0 *m = priv(mcp);
int ret = -ETIME;
int i;
Ser4MCDR2 = reg << 17 | MCDR2_Rd;
writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m));
for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout);
if (Ser4MCSR & MCSR_CRC) {
ret = Ser4MCDR2 & 0xffff;
if (readl_relaxed(MCSR(m)) & MCSR_CRC) {
ret = readl_relaxed(MCDR2(m)) & 0xffff;
break;
}
}
......@@ -116,13 +128,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
static void mcp_sa11x0_enable(struct mcp *mcp)
{
Ser4MCSR = -1;
Ser4MCCR0 |= MCCR0_MCE;
struct mcp_sa11x0 *m = priv(mcp);
writel(-1, MCSR(m));
m->mccr0 |= MCCR0_MCE;
writel_relaxed(m->mccr0, MCCR0(m));
}
static void mcp_sa11x0_disable(struct mcp *mcp)
{
Ser4MCCR0 &= ~MCCR0_MCE;
struct mcp_sa11x0 *m = priv(mcp);
m->mccr0 &= ~MCCR0_MCE;
writel_relaxed(m->mccr0, MCCR0(m));
}
/*
......@@ -137,55 +155,64 @@ static struct mcp_ops mcp_sa11x0 = {
.disable = mcp_sa11x0_disable,
};
static int mcp_sa11x0_probe(struct platform_device *pdev)
static int mcp_sa11x0_probe(struct platform_device *dev)
{
struct mcp_plat_data *data = pdev->dev.platform_data;
struct mcp_plat_data *data = dev->dev.platform_data;
struct resource *mem0, *mem1;
struct mcp_sa11x0 *m;
struct mcp *mcp;
int ret;
if (!data)
return -ENODEV;
if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
return -EBUSY;
mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
if (!mem0 || !mem1)
return -ENXIO;
if (!request_mem_region(mem0->start, resource_size(mem0),
DRIVER_NAME)) {
ret = -EBUSY;
goto err_mem0;
}
if (!request_mem_region(mem1->start, resource_size(mem1),
DRIVER_NAME)) {
ret = -EBUSY;
goto err_mem1;
}
mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0));
if (!mcp) {
ret = -ENOMEM;
goto release;
goto err_alloc;
}
mcp->owner = THIS_MODULE;
mcp->ops = &mcp_sa11x0;
mcp->sclk_rate = data->sclk_rate;
mcp->dma_audio_rd = DMA_Ser4MCP0Rd;
mcp->dma_audio_wr = DMA_Ser4MCP0Wr;
mcp->dma_telco_rd = DMA_Ser4MCP1Rd;
mcp->dma_telco_wr = DMA_Ser4MCP1Wr;
mcp->gpio_base = data->gpio_base;
platform_set_drvdata(pdev, mcp);
m = priv(mcp);
m->mccr0 = data->mccr0 | 0x7f7f;
m->mccr1 = data->mccr1;
if (machine_is_assabet()) {
ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
m->base0 = ioremap(mem0->start, resource_size(mem0));
m->base1 = ioremap(mem1->start, resource_size(mem1));
if (!m->base0 || !m->base1) {
ret = -ENOMEM;
goto err_ioremap;
}
/*
* Setup the PPC unit correctly.
*/
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
platform_set_drvdata(dev, mcp);
/*
* Initialise device. Note that we initially
* set the sampling rate to minimum.
*/
Ser4MCSR = -1;
Ser4MCCR1 = data->mccr1;
Ser4MCCR0 = data->mccr0 | 0x7f7f;
writel_relaxed(-1, MCSR(m));
writel_relaxed(m->mccr1, MCCR1(m));
writel_relaxed(m->mccr0, MCCR0(m));
/*
* Calculate the read/write timeout (us) from the bit clock
......@@ -195,62 +222,90 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
mcp->sclk_rate;
ret = mcp_host_register(mcp);
ret = mcp_host_add(mcp, data->codec_pdata);
if (ret == 0)
goto out;
return 0;
release:
release_mem_region(0x80060000, 0x60);
platform_set_drvdata(pdev, NULL);
platform_set_drvdata(dev, NULL);
out:
err_ioremap:
iounmap(m->base1);
iounmap(m->base0);
mcp_host_free(mcp);
err_alloc:
release_mem_region(mem1->start, resource_size(mem1));
err_mem1:
release_mem_region(mem0->start, resource_size(mem0));
err_mem0:
return ret;
}
static int mcp_sa11x0_remove(struct platform_device *dev)
{
struct mcp *mcp = platform_get_drvdata(dev);
struct mcp_sa11x0 *m = priv(mcp);
struct resource *mem0, *mem1;
if (m->mccr0 & MCCR0_MCE)
dev_warn(&dev->dev,
"device left active (missing disable call?)\n");
mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
platform_set_drvdata(dev, NULL);
mcp_host_unregister(mcp);
release_mem_region(0x80060000, 0x60);
mcp_host_del(mcp);
iounmap(m->base1);
iounmap(m->base0);
mcp_host_free(mcp);
release_mem_region(mem1->start, resource_size(mem1));
release_mem_region(mem0->start, resource_size(mem0));
return 0;
}
static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
#ifdef CONFIG_PM_SLEEP
static int mcp_sa11x0_suspend(struct device *dev)
{
struct mcp *mcp = platform_get_drvdata(dev);
struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
if (m->mccr0 & MCCR0_MCE)
dev_warn(dev, "device left active (missing disable call?)\n");
priv(mcp)->mccr0 = Ser4MCCR0;
priv(mcp)->mccr1 = Ser4MCCR1;
Ser4MCCR0 &= ~MCCR0_MCE;
writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
return 0;
}
static int mcp_sa11x0_resume(struct platform_device *dev)
static int mcp_sa11x0_resume(struct device *dev)
{
struct mcp *mcp = platform_get_drvdata(dev);
struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
Ser4MCCR1 = priv(mcp)->mccr1;
Ser4MCCR0 = priv(mcp)->mccr0;
writel_relaxed(m->mccr1, MCCR1(m));
writel_relaxed(m->mccr0, MCCR0(m));
return 0;
}
#endif
/*
* The driver for the SA11x0 MCP port.
*/
MODULE_ALIAS("platform:sa11x0-mcp");
static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
#ifdef CONFIG_PM_SLEEP
.suspend = mcp_sa11x0_suspend,
.freeze = mcp_sa11x0_suspend,
.poweroff = mcp_sa11x0_suspend,
.resume_noirq = mcp_sa11x0_resume,
.thaw_noirq = mcp_sa11x0_resume,
.restore_noirq = mcp_sa11x0_resume,
#endif
};
static struct platform_driver mcp_sa11x0_driver = {
.probe = mcp_sa11x0_probe,
.remove = mcp_sa11x0_remove,
.suspend = mcp_sa11x0_suspend,
.resume = mcp_sa11x0_resume,
.driver = {
.name = "sa11x0-mcp",
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &mcp_sa11x0_pm_ops,
},
};
......@@ -259,6 +314,7 @@ static struct platform_driver mcp_sa11x0_driver = {
*/
module_platform_driver(mcp_sa11x0_driver);
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
MODULE_LICENSE("GPL");
......@@ -11,14 +11,15 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/mfd/ucb1x00.h>
#include <mach/dma.h>
#define UCB1X00_ATTR(name,input)\
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \
......@@ -38,14 +39,45 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
{
device_create_file(&dev->ucb->dev, &dev_attr_vbatt);
device_create_file(&dev->ucb->dev, &dev_attr_vcharger);
device_create_file(&dev->ucb->dev, &dev_attr_batt_temp);
struct ucb1x00 *ucb = dev->ucb;
struct platform_device *pdev;
struct gpio_keys_platform_data keys;
static struct gpio_keys_button buttons[6];
unsigned i;
memset(buttons, 0, sizeof(buttons));
memset(&keys, 0, sizeof(keys));
for (i = 0; i < ARRAY_SIZE(buttons); i++) {
buttons[i].code = BTN_0 + i;
buttons[i].gpio = ucb->gpio.base + i;
buttons[i].type = EV_KEY;
buttons[i].can_disable = true;
}
keys.buttons = buttons;
keys.nbuttons = ARRAY_SIZE(buttons);
keys.poll_interval = 50;
keys.name = "ucb1x00";
pdev = platform_device_register_data(&ucb->dev, "gpio-keys", -1,
&keys, sizeof(keys));
device_create_file(&ucb->dev, &dev_attr_vbatt);
device_create_file(&ucb->dev, &dev_attr_vcharger);
device_create_file(&ucb->dev, &dev_attr_batt_temp);
dev->priv = pdev;
return 0;
}
static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
{
struct platform_device *pdev = dev->priv;
if (!IS_ERR(pdev))
platform_device_unregister(pdev);
device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp);
device_remove_file(&dev->ucb->dev, &dev_attr_vcharger);
device_remove_file(&dev->ucb->dev, &dev_attr_vbatt);
......
......@@ -23,14 +23,12 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/pm.h>
#include <linux/gpio.h>
#include <linux/semaphore.h>
#include <mach/dma.h>
#include <mach/hardware.h>
static DEFINE_MUTEX(ucb1x00_mutex);
static LIST_HEAD(ucb1x00_drivers);
......@@ -102,7 +100,7 @@ void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear)
* ucb1x00_enable must have been called to enable the comms
* before using this function.
*
* This function does not take any semaphores or spinlocks.
* This function does not take any mutexes or spinlocks.
*/
unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
{
......@@ -120,14 +118,22 @@ static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
else
ucb->io_out &= ~(1 << offset);
ucb1x00_enable(ucb);
ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
ucb1x00_disable(ucb);
spin_unlock_irqrestore(&ucb->io_lock, flags);
}
static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset);
unsigned val;
ucb1x00_enable(ucb);
val = ucb1x00_reg_read(ucb, UCB_IO_DATA);
ucb1x00_disable(ucb);
return val & (1 << offset);
}
static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
......@@ -137,7 +143,9 @@ static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
spin_lock_irqsave(&ucb->io_lock, flags);
ucb->io_dir &= ~(1 << offset);
ucb1x00_enable(ucb);
ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
ucb1x00_disable(ucb);
spin_unlock_irqrestore(&ucb->io_lock, flags);
return 0;
......@@ -157,6 +165,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
else
ucb->io_out &= ~mask;
ucb1x00_enable(ucb);
if (old != ucb->io_out)
ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
......@@ -164,11 +173,19 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
ucb->io_dir |= mask;
ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
}
ucb1x00_disable(ucb);
spin_unlock_irqrestore(&ucb->io_lock, flags);
return 0;
}
static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO;
}
/*
* UCB1300 data sheet says we must:
* 1. enable ADC => 5us (including reference startup time)
......@@ -186,7 +203,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
* Any code wishing to use the ADC converter must call this
* function prior to using it.
*
* This function takes the ADC semaphore to prevent two or more
* This function takes the ADC mutex to prevent two or more
* concurrent uses, and therefore may sleep. As a result, it
* can only be called from process context, not interrupt
* context.
......@@ -196,7 +213,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
*/
void ucb1x00_adc_enable(struct ucb1x00 *ucb)
{
down(&ucb->adc_sem);
mutex_lock(&ucb->adc_mutex);
ucb->adc_cr |= UCB_ADC_ENA;
......@@ -218,7 +235,7 @@ void ucb1x00_adc_enable(struct ucb1x00 *ucb)
* complete (2 frames max without sync).
*
* If called for a synchronised ADC conversion, it may sleep
* with the ADC semaphore held.
* with the ADC mutex held.
*/
unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
{
......@@ -246,7 +263,7 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
* ucb1x00_adc_disable - disable the ADC converter
* @ucb: UCB1x00 structure describing chip
*
* Disable the ADC converter and release the ADC semaphore.
* Disable the ADC converter and release the ADC mutex.
*/
void ucb1x00_adc_disable(struct ucb1x00 *ucb)
{
......@@ -254,7 +271,7 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb)
ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
ucb1x00_disable(ucb);
up(&ucb->adc_sem);
mutex_unlock(&ucb->adc_mutex);
}
/*
......@@ -265,10 +282,9 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb)
* SIBCLK to talk to the chip. We leave the clock running until
* we have finished processing all interrupts from the chip.
*/
static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
static void ucb1x00_irq(unsigned int irq, struct irq_desc *desc)
{
struct ucb1x00 *ucb = devid;
struct ucb1x00_irq *irq;
struct ucb1x00 *ucb = irq_desc_get_handler_data(desc);
unsigned int isr, i;
ucb1x00_enable(ucb);
......@@ -276,157 +292,104 @@ static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++)
if (isr & 1 && irq->fn)
irq->fn(i, irq->devid);
for (i = 0; i < 16 && isr; i++, isr >>= 1, irq++)
if (isr & 1)
generic_handle_irq(ucb->irq_base + i);
ucb1x00_disable(ucb);
return IRQ_HANDLED;
}
/**
* ucb1x00_hook_irq - hook a UCB1x00 interrupt
* @ucb: UCB1x00 structure describing chip
* @idx: interrupt index
* @fn: function to call when interrupt is triggered
* @devid: device id to pass to interrupt handler
*
* Hook the specified interrupt. You can only register one handler
* for each interrupt source. The interrupt source is not enabled
* by this function; use ucb1x00_enable_irq instead.
*
* Interrupt handlers will be called with other interrupts enabled.
*
* Returns zero on success, or one of the following errors:
* -EINVAL if the interrupt index is invalid
* -EBUSY if the interrupt has already been hooked
*/
int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid)
static void ucb1x00_irq_update(struct ucb1x00 *ucb, unsigned mask)
{
struct ucb1x00_irq *irq;
int ret = -EINVAL;
if (idx < 16) {
irq = ucb->irq_handler + idx;
ret = -EBUSY;
spin_lock_irq(&ucb->lock);
if (irq->fn == NULL) {
irq->devid = devid;
irq->fn = fn;
ret = 0;
}
spin_unlock_irq(&ucb->lock);
}
return ret;
ucb1x00_enable(ucb);
if (ucb->irq_ris_enbl & mask)
ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
ucb->irq_mask);
if (ucb->irq_fal_enbl & mask)
ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
ucb->irq_mask);
ucb1x00_disable(ucb);
}
/**
* ucb1x00_enable_irq - enable an UCB1x00 interrupt source
* @ucb: UCB1x00 structure describing chip
* @idx: interrupt index
* @edges: interrupt edges to enable
*
* Enable the specified interrupt to trigger on %UCB_RISING,
* %UCB_FALLING or both edges. The interrupt should have been
* hooked by ucb1x00_hook_irq.
*/
void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
static void ucb1x00_irq_noop(struct irq_data *data)
{
unsigned long flags;
}
if (idx < 16) {
spin_lock_irqsave(&ucb->lock, flags);
static void ucb1x00_irq_mask(struct irq_data *data)
{
struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
unsigned mask = 1 << (data->irq - ucb->irq_base);
ucb1x00_enable(ucb);
if (edges & UCB_RISING) {
ucb->irq_ris_enbl |= 1 << idx;
ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
}
if (edges & UCB_FALLING) {
ucb->irq_fal_enbl |= 1 << idx;
ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
}
ucb1x00_disable(ucb);
spin_unlock_irqrestore(&ucb->lock, flags);
}
raw_spin_lock(&ucb->irq_lock);
ucb->irq_mask &= ~mask;
ucb1x00_irq_update(ucb, mask);
raw_spin_unlock(&ucb->irq_lock);
}
/**
* ucb1x00_disable_irq - disable an UCB1x00 interrupt source
* @ucb: UCB1x00 structure describing chip
* @edges: interrupt edges to disable
*
* Disable the specified interrupt triggering on the specified
* (%UCB_RISING, %UCB_FALLING or both) edges.
*/
void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
static void ucb1x00_irq_unmask(struct irq_data *data)
{
unsigned long flags;
if (idx < 16) {
spin_lock_irqsave(&ucb->lock, flags);
struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
unsigned mask = 1 << (data->irq - ucb->irq_base);
ucb1x00_enable(ucb);
if (edges & UCB_RISING) {
ucb->irq_ris_enbl &= ~(1 << idx);
ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
}
if (edges & UCB_FALLING) {
ucb->irq_fal_enbl &= ~(1 << idx);
ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
}
ucb1x00_disable(ucb);
spin_unlock_irqrestore(&ucb->lock, flags);
}
raw_spin_lock(&ucb->irq_lock);
ucb->irq_mask |= mask;
ucb1x00_irq_update(ucb, mask);
raw_spin_unlock(&ucb->irq_lock);
}
/**
* ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt
* @ucb: UCB1x00 structure describing chip
* @idx: interrupt index
* @devid: device id.
*
* Disable the interrupt source and remove the handler. devid must
* match the devid passed when hooking the interrupt.
*
* Returns zero on success, or one of the following errors:
* -EINVAL if the interrupt index is invalid
* -ENOENT if devid does not match
*/
int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid)
static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type)
{
struct ucb1x00_irq *irq;
int ret;
if (idx >= 16)
goto bad;
struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
unsigned mask = 1 << (data->irq - ucb->irq_base);
irq = ucb->irq_handler + idx;
ret = -ENOENT;
raw_spin_lock(&ucb->irq_lock);
if (type & IRQ_TYPE_EDGE_RISING)
ucb->irq_ris_enbl |= mask;
else
ucb->irq_ris_enbl &= ~mask;
spin_lock_irq(&ucb->lock);
if (irq->devid == devid) {
ucb->irq_ris_enbl &= ~(1 << idx);
ucb->irq_fal_enbl &= ~(1 << idx);
if (type & IRQ_TYPE_EDGE_FALLING)
ucb->irq_fal_enbl |= mask;
else
ucb->irq_fal_enbl &= ~mask;
if (ucb->irq_mask & mask) {
ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
ucb->irq_mask);
ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
ucb->irq_mask);
}
raw_spin_unlock(&ucb->irq_lock);
ucb1x00_enable(ucb);
ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
ucb1x00_disable(ucb);
return 0;
}
irq->fn = NULL;
irq->devid = NULL;
ret = 0;
}
spin_unlock_irq(&ucb->lock);
return ret;
static int ucb1x00_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
struct ucb1x00_plat_data *pdata = ucb->mcp->attached_device.platform_data;
unsigned mask = 1 << (data->irq - ucb->irq_base);
bad:
printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx);
if (!pdata || !pdata->can_wakeup)
return -EINVAL;
raw_spin_lock(&ucb->irq_lock);
if (on)
ucb->irq_wake |= mask;
else
ucb->irq_wake &= ~mask;
raw_spin_unlock(&ucb->irq_lock);
return 0;
}
static struct irq_chip ucb1x00_irqchip = {
.name = "ucb1x00",
.irq_ack = ucb1x00_irq_noop,
.irq_mask = ucb1x00_irq_mask,
.irq_unmask = ucb1x00_irq_unmask,
.irq_set_type = ucb1x00_irq_set_type,
.irq_set_wake = ucb1x00_irq_set_wake,
};
static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
{
struct ucb1x00_dev *dev;
......@@ -440,8 +403,8 @@ static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
ret = drv->add(dev);
if (ret == 0) {
list_add(&dev->dev_node, &ucb->devs);
list_add(&dev->drv_node, &drv->devs);
list_add_tail(&dev->dev_node, &ucb->devs);
list_add_tail(&dev->drv_node, &drv->devs);
} else {
kfree(dev);
}
......@@ -533,98 +496,126 @@ static struct class ucb1x00_class = {
static int ucb1x00_probe(struct mcp *mcp)
{
struct ucb1x00 *ucb;
struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
struct ucb1x00_driver *drv;
unsigned int id;
struct ucb1x00 *ucb;
unsigned id, i, irq_base;
int ret = -ENODEV;
int temp;
/* Tell the platform to deassert the UCB1x00 reset */
if (pdata && pdata->reset)
pdata->reset(UCB_RST_PROBE);
mcp_enable(mcp);
id = mcp_reg_read(mcp, UCB_ID);
mcp_disable(mcp);
if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
goto err_disable;
goto out;
}
ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
ret = -ENOMEM;
if (!ucb)
goto err_disable;
goto out;
device_initialize(&ucb->dev);
ucb->dev.class = &ucb1x00_class;
ucb->dev.parent = &mcp->attached_device;
dev_set_name(&ucb->dev, "ucb1x00");
spin_lock_init(&ucb->lock);
raw_spin_lock_init(&ucb->irq_lock);
spin_lock_init(&ucb->io_lock);
sema_init(&ucb->adc_sem, 1);
mutex_init(&ucb->adc_mutex);
ucb->id = id;
ucb->mcp = mcp;
ret = device_add(&ucb->dev);
if (ret)
goto err_dev_add;
ucb1x00_enable(ucb);
ucb->irq = ucb1x00_detect_irq(ucb);
ucb1x00_disable(ucb);
if (ucb->irq == NO_IRQ) {
printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
dev_err(&ucb->dev, "IRQ probe failed\n");
ret = -ENODEV;
goto err_free;
goto err_no_irq;
}
ucb->gpio.base = -1;
if (mcp->gpio_base != 0) {
irq_base = pdata ? pdata->irq_base : 0;
ucb->irq_base = irq_alloc_descs(-1, irq_base, 16, -1);
if (ucb->irq_base < 0) {
dev_err(&ucb->dev, "unable to allocate 16 irqs: %d\n",
ucb->irq_base);
goto err_irq_alloc;
}
for (i = 0; i < 16; i++) {
unsigned irq = ucb->irq_base + i;
irq_set_chip_and_handler(irq, &ucb1x00_irqchip, handle_edge_irq);
irq_set_chip_data(irq, ucb);
set_irq_flags(irq, IRQF_VALID | IRQ_NOREQUEST);
}
irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING);
irq_set_handler_data(ucb->irq, ucb);
irq_set_chained_handler(ucb->irq, ucb1x00_irq);
if (pdata && pdata->gpio_base) {
ucb->gpio.label = dev_name(&ucb->dev);
ucb->gpio.base = mcp->gpio_base;
ucb->gpio.dev = &ucb->dev;
ucb->gpio.owner = THIS_MODULE;
ucb->gpio.base = pdata->gpio_base;
ucb->gpio.ngpio = 10;
ucb->gpio.set = ucb1x00_gpio_set;
ucb->gpio.get = ucb1x00_gpio_get;
ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
ucb->gpio.to_irq = ucb1x00_to_irq;
ret = gpiochip_add(&ucb->gpio);
if (ret)
goto err_free;
goto err_gpio_add;
} else
dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
"UCB1x00", ucb);
if (ret) {
printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
ucb->irq, ret);
goto err_gpio;
}
mcp_set_drvdata(mcp, ucb);
ret = device_register(&ucb->dev);
if (ret)
goto err_irq;
if (pdata)
device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup);
INIT_LIST_HEAD(&ucb->devs);
mutex_lock(&ucb1x00_mutex);
list_add(&ucb->node, &ucb1x00_devices);
list_add_tail(&ucb->node, &ucb1x00_devices);
list_for_each_entry(drv, &ucb1x00_drivers, node) {
ucb1x00_add_dev(ucb, drv);
}
mutex_unlock(&ucb1x00_mutex);
goto out;
return ret;
err_irq:
free_irq(ucb->irq, ucb);
err_gpio:
if (ucb->gpio.base != -1)
temp = gpiochip_remove(&ucb->gpio);
err_free:
kfree(ucb);
err_disable:
mcp_disable(mcp);
err_gpio_add:
irq_set_chained_handler(ucb->irq, NULL);
err_irq_alloc:
if (ucb->irq_base > 0)
irq_free_descs(ucb->irq_base, 16);
err_no_irq:
device_del(&ucb->dev);
err_dev_add:
put_device(&ucb->dev);
out:
if (pdata && pdata->reset)
pdata->reset(UCB_RST_PROBE_FAIL);
return ret;
}
static void ucb1x00_remove(struct mcp *mcp)
{
struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
struct list_head *l, *n;
int ret;
......@@ -643,8 +634,12 @@ static void ucb1x00_remove(struct mcp *mcp)
dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
}
free_irq(ucb->irq, ucb);
irq_set_chained_handler(ucb->irq, NULL);
irq_free_descs(ucb->irq_base, 16);
device_unregister(&ucb->dev);
if (pdata && pdata->reset)
pdata->reset(UCB_RST_REMOVE);
}
int ucb1x00_register_driver(struct ucb1x00_driver *drv)
......@@ -653,7 +648,7 @@ int ucb1x00_register_driver(struct ucb1x00_driver *drv)
INIT_LIST_HEAD(&drv->devs);
mutex_lock(&ucb1x00_mutex);
list_add(&drv->node, &ucb1x00_drivers);
list_add_tail(&drv->node, &ucb1x00_drivers);
list_for_each_entry(ucb, &ucb1x00_devices, node) {
ucb1x00_add_dev(ucb, drv);
}
......@@ -674,44 +669,86 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv)
mutex_unlock(&ucb1x00_mutex);
}
static int ucb1x00_suspend(struct mcp *mcp, pm_message_t state)
static int ucb1x00_suspend(struct device *dev)
{
struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
struct ucb1x00_dev *dev;
struct ucb1x00_plat_data *pdata = dev->platform_data;
struct ucb1x00 *ucb = dev_get_drvdata(dev);
struct ucb1x00_dev *udev;
mutex_lock(&ucb1x00_mutex);
list_for_each_entry(dev, &ucb->devs, dev_node) {
if (dev->drv->suspend)
dev->drv->suspend(dev, state);
list_for_each_entry(udev, &ucb->devs, dev_node) {
if (udev->drv->suspend)
udev->drv->suspend(udev);
}
mutex_unlock(&ucb1x00_mutex);
if (ucb->irq_wake) {
unsigned long flags;
raw_spin_lock_irqsave(&ucb->irq_lock, flags);
ucb1x00_enable(ucb);
ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
ucb->irq_wake);
ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
ucb->irq_wake);
ucb1x00_disable(ucb);
raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
enable_irq_wake(ucb->irq);
} else if (pdata && pdata->reset)
pdata->reset(UCB_RST_SUSPEND);
return 0;
}
static int ucb1x00_resume(struct mcp *mcp)
static int ucb1x00_resume(struct device *dev)
{
struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
struct ucb1x00_dev *dev;
struct ucb1x00_plat_data *pdata = dev->platform_data;
struct ucb1x00 *ucb = dev_get_drvdata(dev);
struct ucb1x00_dev *udev;
if (!ucb->irq_wake && pdata && pdata->reset)
pdata->reset(UCB_RST_RESUME);
ucb1x00_enable(ucb);
ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
if (ucb->irq_wake) {
unsigned long flags;
raw_spin_lock_irqsave(&ucb->irq_lock, flags);
ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
ucb->irq_mask);
ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
ucb->irq_mask);
raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
disable_irq_wake(ucb->irq);
}
ucb1x00_disable(ucb);
mutex_lock(&ucb1x00_mutex);
list_for_each_entry(dev, &ucb->devs, dev_node) {
if (dev->drv->resume)
dev->drv->resume(dev);
list_for_each_entry(udev, &ucb->devs, dev_node) {
if (udev->drv->resume)
udev->drv->resume(udev);
}
mutex_unlock(&ucb1x00_mutex);
return 0;
}
static const struct dev_pm_ops ucb1x00_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume)
};
static struct mcp_driver ucb1x00_driver = {
.drv = {
.name = "ucb1x00",
.owner = THIS_MODULE,
.pm = &ucb1x00_pm_ops,
},
.probe = ucb1x00_probe,
.remove = ucb1x00_remove,
.suspend = ucb1x00_suspend,
.resume = ucb1x00_resume,
};
static int __init ucb1x00_init(void)
......@@ -742,14 +779,10 @@ EXPORT_SYMBOL(ucb1x00_adc_enable);
EXPORT_SYMBOL(ucb1x00_adc_read);
EXPORT_SYMBOL(ucb1x00_adc_disable);
EXPORT_SYMBOL(ucb1x00_hook_irq);
EXPORT_SYMBOL(ucb1x00_free_irq);
EXPORT_SYMBOL(ucb1x00_enable_irq);
EXPORT_SYMBOL(ucb1x00_disable_irq);
EXPORT_SYMBOL(ucb1x00_register_driver);
EXPORT_SYMBOL(ucb1x00_unregister_driver);
MODULE_ALIAS("mcp:ucb1x00");
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("UCB1x00 core driver");
MODULE_LICENSE("GPL");
......@@ -20,8 +20,9 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/string.h>
......@@ -32,7 +33,6 @@
#include <linux/kthread.h>
#include <linux/mfd/ucb1x00.h>
#include <mach/dma.h>
#include <mach/collie.h>
#include <asm/mach-types.h>
......@@ -42,6 +42,8 @@ struct ucb1x00_ts {
struct input_dev *idev;
struct ucb1x00 *ucb;
spinlock_t irq_lock;
unsigned irq_disabled;
wait_queue_head_t irq_wait;
struct task_struct *rtask;
u16 x_res;
......@@ -238,7 +240,12 @@ static int ucb1x00_thread(void *_ts)
if (ucb1x00_ts_pen_down(ts)) {
set_current_state(TASK_INTERRUPTIBLE);
ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
spin_lock_irq(&ts->irq_lock);
if (ts->irq_disabled) {
ts->irq_disabled = 0;
enable_irq(ts->ucb->irq_base + UCB_IRQ_TSPX);
}
spin_unlock_irq(&ts->irq_lock);
ucb1x00_disable(ts->ucb);
/*
......@@ -281,23 +288,37 @@ static int ucb1x00_thread(void *_ts)
* We only detect touch screen _touches_ with this interrupt
* handler, and even then we just schedule our task.
*/
static void ucb1x00_ts_irq(int idx, void *id)
static irqreturn_t ucb1x00_ts_irq(int irq, void *id)
{
struct ucb1x00_ts *ts = id;
ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
spin_lock(&ts->irq_lock);
ts->irq_disabled = 1;
disable_irq_nosync(ts->ucb->irq_base + UCB_IRQ_TSPX);
spin_unlock(&ts->irq_lock);
wake_up(&ts->irq_wait);
return IRQ_HANDLED;
}
static int ucb1x00_ts_open(struct input_dev *idev)
{
struct ucb1x00_ts *ts = input_get_drvdata(idev);
unsigned long flags = 0;
int ret = 0;
BUG_ON(ts->rtask);
if (machine_is_collie())
flags = IRQF_TRIGGER_RISING;
else
flags = IRQF_TRIGGER_FALLING;
ts->irq_disabled = 0;
init_waitqueue_head(&ts->irq_wait);
ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
ret = request_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ucb1x00_ts_irq,
flags, "ucb1x00-ts", ts);
if (ret < 0)
goto out;
......@@ -314,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev)
if (!IS_ERR(ts->rtask)) {
ret = 0;
} else {
ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
ts->rtask = NULL;
ret = -EFAULT;
}
......@@ -334,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev)
kthread_stop(ts->rtask);
ucb1x00_enable(ts->ucb);
ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
ucb1x00_disable(ts->ucb);
}
......@@ -359,11 +380,13 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
ts->ucb = dev->ucb;
ts->idev = idev;
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
spin_lock_init(&ts->irq_lock);
idev->name = "Touchscreen panel";
idev->id.product = ts->ucb->id;
idev->open = ucb1x00_ts_open;
idev->close = ucb1x00_ts_close;
idev->dev.parent = &ts->ucb->dev;
idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
......
......@@ -23,106 +23,6 @@
#include <asm/sizes.h>
#include <asm/mach/flash.h>
#if 0
/*
* This is here for documentation purposes only - until these people
* submit their machine types. It will be gone January 2005.
*/
static struct mtd_partition consus_partitions[] = {
{
.name = "Consus boot firmware",
.offset = 0,
.size = 0x00040000,
.mask_flags = MTD_WRITABLE, /* force read-only */
}, {
.name = "Consus kernel",
.offset = 0x00040000,
.size = 0x00100000,
.mask_flags = 0,
}, {
.name = "Consus disk",
.offset = 0x00140000,
/* The rest (up to 16M) for jffs. We could put 0 and
make it find the size automatically, but right now
i have 32 megs. jffs will use all 32 megs if given
the chance, and this leads to horrible problems
when you try to re-flash the image because blob
won't erase the whole partition. */
.size = 0x01000000 - 0x00140000,
.mask_flags = 0,
}, {
/* this disk is a secondary disk, which can be used as
needed, for simplicity, make it the size of the other
consus partition, although realistically it could be
the remainder of the disk (depending on the file
system used) */
.name = "Consus disk2",
.offset = 0x01000000,
.size = 0x01000000 - 0x00140000,
.mask_flags = 0,
}
};
/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
static struct mtd_partition frodo_partitions[] =
{
{
.name = "bootloader",
.size = 0x00040000,
.offset = 0x00000000,
.mask_flags = MTD_WRITEABLE
}, {
.name = "bootloader params",
.size = 0x00040000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE
}, {
.name = "kernel",
.size = 0x00100000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE
}, {
.name = "ramdisk",
.size = 0x00400000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE
}, {
.name = "file system",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND
}
};
static struct mtd_partition jornada56x_partitions[] = {
{
.name = "bootldr",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "rootfs",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
static void jornada56x_set_vpp(int vpp)
{
if (vpp)
GPSR = GPIO_GPIO26;
else
GPCR = GPIO_GPIO26;
GPDR |= GPIO_GPIO26;
}
/*
* Machine Phys Size set_vpp
* Consus : SA1100_CS0_PHYS SZ_32M
* Frodo : SA1100_CS0_PHYS SZ_32M
* Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
*/
#endif
struct sa_subdev_info {
char name[16];
struct map_info map;
......@@ -373,21 +273,9 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static void sa1100_mtd_shutdown(struct platform_device *dev)
{
struct sa_info *info = platform_get_drvdata(dev);
if (info && mtd_suspend(info->mtd) == 0)
mtd_resume(info->mtd);
}
#else
#define sa1100_mtd_shutdown NULL
#endif
static struct platform_driver sa1100_mtd_driver = {
.probe = sa1100_mtd_probe,
.remove = __exit_p(sa1100_mtd_remove),
.shutdown = sa1100_mtd_shutdown,
.driver = {
.name = "sa1100-mtd",
.owner = THIS_MODULE,
......
......@@ -2281,7 +2281,7 @@ static int __devinit smc_drv_probe(struct platform_device *pdev)
if (ret)
goto out_release_io;
#if defined(CONFIG_SA1100_ASSABET)
NCR_0 |= NCR_ENET_OSC_EN;
neponset_ncr_set(NCR_ENET_OSC_EN);
#endif
platform_set_drvdata(pdev, ndev);
ret = smc_enable_device(pdev);
......
......@@ -356,7 +356,7 @@ config VLSI_FIR
config SA1100_FIR
tristate "SA1100 Internal IR"
depends on ARCH_SA1100 && IRDA
depends on ARCH_SA1100 && IRDA && DMA_SA11X0
config VIA_FIR
tristate "VIA VT8231/VT1211 SIR/MIR/FIR"
......
......@@ -15,7 +15,7 @@
* This driver takes one kernel command line parameter, sa1100ir=, with
* the following options:
* max_rate:baudrate - set the maximum baud rate
* power_leve:level - set the transmitter power level
* power_level:level - set the transmitter power level
* tx_lpm:0|1 - set transmit low power mode
*/
#include <linux/module.h>
......@@ -30,13 +30,13 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/sa11x0-dma.h>
#include <net/irda/irda.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
#include <asm/irq.h>
#include <mach/dma.h>
#include <mach/hardware.h>
#include <asm/mach/irda.h>
......@@ -44,8 +44,15 @@ static int power_level = 3;
static int tx_lpm;
static int max_rate = 4000000;
struct sa1100_buf {
struct device *dev;
struct sk_buff *skb;
struct scatterlist sg;
struct dma_chan *chan;
dma_cookie_t cookie;
};
struct sa1100_irda {
unsigned char hscr0;
unsigned char utcr4;
unsigned char power;
unsigned char open;
......@@ -53,12 +60,8 @@ struct sa1100_irda {
int speed;
int newspeed;
struct sk_buff *txskb;
struct sk_buff *rxskb;
dma_addr_t txbuf_dma;
dma_addr_t rxbuf_dma;
dma_regs_t *txdma;
dma_regs_t *rxdma;
struct sa1100_buf dma_rx;
struct sa1100_buf dma_tx;
struct device *dev;
struct irda_platform_data *pdata;
......@@ -67,23 +70,103 @@ struct sa1100_irda {
iobuff_t tx_buff;
iobuff_t rx_buff;
int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *);
irqreturn_t (*irq)(struct net_device *, struct sa1100_irda *);
};
static int sa1100_irda_set_speed(struct sa1100_irda *, int);
#define IS_FIR(si) ((si)->speed >= 4000000)
#define HPSIR_MAX_RXLEN 2047
static struct dma_slave_config sa1100_irda_sir_tx = {
.direction = DMA_TO_DEVICE,
.dst_addr = __PREG(Ser2UTDR),
.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.dst_maxburst = 4,
};
static struct dma_slave_config sa1100_irda_fir_rx = {
.direction = DMA_FROM_DEVICE,
.src_addr = __PREG(Ser2HSDR),
.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.src_maxburst = 8,
};
static struct dma_slave_config sa1100_irda_fir_tx = {
.direction = DMA_TO_DEVICE,
.dst_addr = __PREG(Ser2HSDR),
.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.dst_maxburst = 8,
};
static unsigned sa1100_irda_dma_xferred(struct sa1100_buf *buf)
{
struct dma_chan *chan = buf->chan;
struct dma_tx_state state;
enum dma_status status;
status = chan->device->device_tx_status(chan, buf->cookie, &state);
if (status != DMA_PAUSED)
return 0;
return sg_dma_len(&buf->sg) - state.residue;
}
static int sa1100_irda_dma_request(struct device *dev, struct sa1100_buf *buf,
const char *name, struct dma_slave_config *cfg)
{
dma_cap_mask_t m;
int ret;
dma_cap_zero(m);
dma_cap_set(DMA_SLAVE, m);
buf->chan = dma_request_channel(m, sa11x0_dma_filter_fn, (void *)name);
if (!buf->chan) {
dev_err(dev, "unable to request DMA channel for %s\n",
name);
return -ENOENT;
}
ret = dmaengine_slave_config(buf->chan, cfg);
if (ret)
dev_warn(dev, "DMA slave_config for %s returned %d\n",
name, ret);
buf->dev = buf->chan->device->dev;
return 0;
}
static void sa1100_irda_dma_start(struct sa1100_buf *buf,
enum dma_transfer_direction dir, dma_async_tx_callback cb, void *cb_p)
{
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = buf->chan;
desc = chan->device->device_prep_slave_sg(chan, &buf->sg, 1, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (desc) {
desc->callback = cb;
desc->callback_param = cb_p;
buf->cookie = dmaengine_submit(desc);
dma_async_issue_pending(chan);
}
}
/*
* Allocate and map the receive buffer, unless it is already allocated.
*/
static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
{
if (si->rxskb)
if (si->dma_rx.skb)
return 0;
si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
if (!si->rxskb) {
si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
if (!si->dma_rx.skb) {
printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n");
return -ENOMEM;
}
......@@ -92,11 +175,14 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
* Align any IP headers that may be contained
* within the frame.
*/
skb_reserve(si->rxskb, 1);
skb_reserve(si->dma_rx.skb, 1);
sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN);
if (dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) {
dev_kfree_skb_any(si->dma_rx.skb);
return -ENOMEM;
}
si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
HPSIR_MAX_RXLEN,
DMA_FROM_DEVICE);
return 0;
}
......@@ -106,7 +192,7 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
*/
static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
{
if (!si->rxskb) {
if (!si->dma_rx.skb) {
printk(KERN_ERR "sa1100_ir: rx buffer went missing\n");
return;
}
......@@ -114,254 +200,87 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
/*
* First empty receive FIFO
*/
Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
Ser2HSCR0 = HSCR0_HSSP;
/*
* Enable the DMA, receiver and receive interrupt.
*/
sa1100_clear_dma(si->rxdma);
sa1100_start_dma(si->rxdma, si->rxbuf_dma, HPSIR_MAX_RXLEN);
Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE;
dmaengine_terminate_all(si->dma_rx.chan);
sa1100_irda_dma_start(&si->dma_rx, DMA_DEV_TO_MEM, NULL, NULL);
Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE;
}
/*
* Set the IrDA communications speed.
*/
static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
static void sa1100_irda_check_speed(struct sa1100_irda *si)
{
unsigned long flags;
int brd, ret = -EINVAL;
switch (speed) {
case 9600: case 19200: case 38400:
case 57600: case 115200:
brd = 3686400 / (16 * speed) - 1;
/*
* Stop the receive DMA.
*/
if (IS_FIR(si))
sa1100_stop_dma(si->rxdma);
local_irq_save(flags);
Ser2UTCR3 = 0;
Ser2HSCR0 = HSCR0_UART;
Ser2UTCR1 = brd >> 8;
Ser2UTCR2 = brd;
/*
* Clear status register
*/
Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
if (si->pdata->set_speed)
si->pdata->set_speed(si->dev, speed);
si->speed = speed;
local_irq_restore(flags);
ret = 0;
break;
case 4000000:
local_irq_save(flags);
si->hscr0 = 0;
Ser2HSSR0 = 0xff;
Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
Ser2UTCR3 = 0;
si->speed = speed;
if (si->pdata->set_speed)
si->pdata->set_speed(si->dev, speed);
sa1100_irda_rx_alloc(si);
sa1100_irda_rx_dma_start(si);
local_irq_restore(flags);
break;
default:
break;
if (si->newspeed) {
sa1100_irda_set_speed(si, si->newspeed);
si->newspeed = 0;
}
return ret;
}
/*
* Control the power state of the IrDA transmitter.
* State:
* 0 - off
* 1 - short range, lowest power
* 2 - medium range, medium power
* 3 - maximum range, high power
*
* Currently, only assabet is known to support this.
* HP-SIR format support.
*/
static int
__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state)
{
int ret = 0;
if (si->pdata->set_power)
ret = si->pdata->set_power(si->dev, state);
return ret;
}
static inline int
sa1100_set_power(struct sa1100_irda *si, unsigned int state)
{
int ret;
ret = __sa1100_irda_set_power(si, state);
if (ret == 0)
si->power = state;
return ret;
}
static int sa1100_irda_startup(struct sa1100_irda *si)
static void sa1100_irda_sirtxdma_irq(void *id)
{
int ret;
struct net_device *dev = id;
struct sa1100_irda *si = netdev_priv(dev);
/*
* Ensure that the ports for this device are setup correctly.
*/
if (si->pdata->startup) {
ret = si->pdata->startup(si->dev);
if (ret)
return ret;
}
dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE);
dev_kfree_skb(si->dma_tx.skb);
si->dma_tx.skb = NULL;
/*
* Configure PPC for IRDA - we want to drive TXD2 low.
* We also want to drive this pin low during sleep.
*/
PPSR &= ~PPC_TXD2;
PSDR &= ~PPC_TXD2;
PPDR |= PPC_TXD2;
dev->stats.tx_packets++;
dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg);
/*
* Enable HP-SIR modulation, and ensure that the port is disabled.
*/
Ser2UTCR3 = 0;
Ser2HSCR0 = HSCR0_UART;
Ser2UTCR4 = si->utcr4;
Ser2UTCR0 = UTCR0_8BitData;
Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL;
/* We need to ensure that the transmitter has finished. */
do
rmb();
while (Ser2UTSR1 & UTSR1_TBY);
/*
* Clear status register
* Ok, we've finished transmitting. Now enable the receiver.
* Sometimes we get a receive IRQ immediately after a transmit...
*/
Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
ret = sa1100_irda_set_speed(si, si->speed = 9600);
if (ret) {
Ser2UTCR3 = 0;
Ser2HSCR0 = 0;
if (si->pdata->shutdown)
si->pdata->shutdown(si->dev);
}
return ret;
}
static void sa1100_irda_shutdown(struct sa1100_irda *si)
{
/*
* Stop all DMA activity.
*/
sa1100_stop_dma(si->rxdma);
sa1100_stop_dma(si->txdma);
/* Disable the port. */
Ser2UTCR3 = 0;
Ser2HSCR0 = 0;
if (si->pdata->shutdown)
si->pdata->shutdown(si->dev);
}
#ifdef CONFIG_PM
/*
* Suspend the IrDA interface.
*/
static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sa1100_irda *si;
if (!dev)
return 0;
sa1100_irda_check_speed(si);
si = netdev_priv(dev);
if (si->open) {
/*
* Stop the transmit queue
*/
netif_device_detach(dev);
disable_irq(dev->irq);
sa1100_irda_shutdown(si);
__sa1100_irda_set_power(si, 0);
}
return 0;
/* I'm hungry! */
netif_wake_queue(dev);
}
/*
* Resume the IrDA interface.
*/
static int sa1100_irda_resume(struct platform_device *pdev)
static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
struct sa1100_irda *si)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sa1100_irda *si;
if (!dev)
return 0;
si->tx_buff.data = si->tx_buff.head;
si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data,
si->tx_buff.truesize);
si = netdev_priv(dev);
if (si->open) {
/*
* If we missed a speed change, initialise at the new speed
* directly. It is debatable whether this is actually
* required, but in the interests of continuing from where
* we left off it is desirable. The converse argument is
* that we should re-negotiate at 9600 baud again.
*/
if (si->newspeed) {
si->speed = si->newspeed;
si->newspeed = 0;
si->dma_tx.skb = skb;
sg_set_buf(&si->dma_tx.sg, si->tx_buff.data, si->tx_buff.len);
if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
si->dma_tx.skb = NULL;
netif_wake_queue(dev);
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
sa1100_irda_startup(si);
__sa1100_irda_set_power(si, si->power);
enable_irq(dev->irq);
sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, dev);
/*
* This automatically wakes up the queue
* The mean turn-around time is enforced by XBOF padding,
* so we don't have to do anything special here.
*/
netif_device_attach(dev);
}
Ser2UTCR3 = UTCR3_TXE;
return 0;
return NETDEV_TX_OK;
}
#else
#define sa1100_irda_suspend NULL
#define sa1100_irda_resume NULL
#endif
/*
* HP-SIR format interrupt service routines.
*/
static void sa1100_irda_hpsir_irq(struct net_device *dev)
static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si)
{
struct sa1100_irda *si = netdev_priv(dev);
int status;
status = Ser2UTSR0;
......@@ -414,51 +333,96 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
}
if (status & UTSR0_TFS && si->tx_buff.len) {
/*
* Transmitter FIFO is not full
*/
do {
Ser2UTDR = *si->tx_buff.data++;
si->tx_buff.len -= 1;
} while (Ser2UTSR1 & UTSR1_TNF && si->tx_buff.len);
return IRQ_HANDLED;
}
if (si->tx_buff.len == 0) {
dev->stats.tx_packets++;
dev->stats.tx_bytes += si->tx_buff.data -
si->tx_buff.head;
/*
* FIR format support.
*/
static void sa1100_irda_firtxdma_irq(void *id)
{
struct net_device *dev = id;
struct sa1100_irda *si = netdev_priv(dev);
struct sk_buff *skb;
/*
* We need to ensure that the transmitter has
* finished.
* Wait for the transmission to complete. Unfortunately,
* the hardware doesn't give us an interrupt to indicate
* "end of frame".
*/
do
rmb();
while (Ser2UTSR1 & UTSR1_TBY);
while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);
/*
* Ok, we've finished transmitting. Now enable
* the receiver. Sometimes we get a receive IRQ
* immediately after a transmit...
* Clear the transmit underrun bit.
*/
Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
Ser2HSSR0 = HSSR0_TUR;
if (si->newspeed) {
sa1100_irda_set_speed(si, si->newspeed);
si->newspeed = 0;
/*
* Do we need to change speed? Note that we're lazy
* here - we don't free the old dma_rx.skb. We don't need
* to allocate a buffer either.
*/
sa1100_irda_check_speed(si);
/*
* Start reception. This disables the transmitter for
* us. This will be using the existing RX buffer.
*/
sa1100_irda_rx_dma_start(si);
/* Account and free the packet. */
skb = si->dma_tx.skb;
if (skb) {
dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
DMA_TO_DEVICE);
dev->stats.tx_packets ++;
dev->stats.tx_bytes += skb->len;
dev_kfree_skb_irq(skb);
si->dma_tx.skb = NULL;
}
/* I'm hungry! */
/*
* Make sure that the TX queue is available for sending
* (for retries). TX has priority over RX at all times.
*/
netif_wake_queue(dev);
}
static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
struct sa1100_irda *si)
{
int mtt = irda_get_mtt(skb);
si->dma_tx.skb = skb;
sg_set_buf(&si->dma_tx.sg, skb->data, skb->len);
if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
si->dma_tx.skb = NULL;
netif_wake_queue(dev);
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
}
sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_firtxdma_irq, dev);
/*
* If we have a mean turn-around time, impose the specified
* specified delay. We could shorten this by timing from
* the point we received the packet.
*/
if (mtt)
udelay(mtt);
Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE;
return NETDEV_TX_OK;
}
static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
{
struct sk_buff *skb = si->rxskb;
dma_addr_t dma_addr;
struct sk_buff *skb = si->dma_rx.skb;
unsigned int len, stat, data;
if (!skb) {
......@@ -469,11 +433,10 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
/*
* Get the current data position.
*/
dma_addr = sa1100_get_dma_pos(si->rxdma);
len = dma_addr - si->rxbuf_dma;
len = sa1100_irda_dma_xferred(&si->dma_rx);
if (len > HPSIR_MAX_RXLEN)
len = HPSIR_MAX_RXLEN;
dma_unmap_single(si->dev, si->rxbuf_dma, len, DMA_FROM_DEVICE);
dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
do {
/*
......@@ -501,7 +464,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
} while (Ser2HSSR0 & HSSR0_EIF);
if (stat & HSSR1_EOF) {
si->rxskb = NULL;
si->dma_rx.skb = NULL;
skb_put(skb, len);
skb->dev = dev;
......@@ -518,28 +481,23 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
netif_rx(skb);
} else {
/*
* Remap the buffer.
* Remap the buffer - it was previously mapped, and we
* hope that this succeeds.
*/
si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
HPSIR_MAX_RXLEN,
DMA_FROM_DEVICE);
dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
}
}
/*
* FIR format interrupt service routine. We only have to
* handle RX events; transmit events go via the TX DMA handler.
*
* No matter what, we disable RX, process, and the restart RX.
* We only have to handle RX events here; transmit events go via the TX
* DMA handler. We disable RX, process, and the restart RX.
*/
static void sa1100_irda_fir_irq(struct net_device *dev)
static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si)
{
struct sa1100_irda *si = netdev_priv(dev);
/*
* Stop RX DMA
*/
sa1100_stop_dma(si->rxdma);
dmaengine_pause(si->dma_rx.chan);
/*
* Framing error - we throw away the packet completely.
......@@ -555,7 +513,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev)
/*
* Clear out the DMA...
*/
Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
Ser2HSCR0 = HSCR0_HSSP;
/*
* Clear selected status bits now, so we
......@@ -573,78 +531,128 @@ static void sa1100_irda_fir_irq(struct net_device *dev)
if (Ser2HSSR0 & HSSR0_EIF)
sa1100_irda_fir_error(si, dev);
/*
* No matter what happens, we must restart reception.
*/
sa1100_irda_rx_dma_start(si);
/*
* No matter what happens, we must restart reception.
*/
sa1100_irda_rx_dma_start(si);
return IRQ_HANDLED;
}
/*
* Set the IrDA communications speed.
*/
static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
{
unsigned long flags;
int brd, ret = -EINVAL;
switch (speed) {
case 9600: case 19200: case 38400:
case 57600: case 115200:
brd = 3686400 / (16 * speed) - 1;
/* Stop the receive DMA, and configure transmit. */
if (IS_FIR(si)) {
dmaengine_terminate_all(si->dma_rx.chan);
dmaengine_slave_config(si->dma_tx.chan,
&sa1100_irda_sir_tx);
}
local_irq_save(flags);
Ser2UTCR3 = 0;
Ser2HSCR0 = HSCR0_UART;
Ser2UTCR1 = brd >> 8;
Ser2UTCR2 = brd;
/*
* Clear status register
*/
Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
if (si->pdata->set_speed)
si->pdata->set_speed(si->dev, speed);
si->speed = speed;
si->tx_start = sa1100_irda_sir_tx_start;
si->irq = sa1100_irda_sir_irq;
local_irq_restore(flags);
ret = 0;
break;
case 4000000:
if (!IS_FIR(si))
dmaengine_slave_config(si->dma_tx.chan,
&sa1100_irda_fir_tx);
local_irq_save(flags);
Ser2HSSR0 = 0xff;
Ser2HSCR0 = HSCR0_HSSP;
Ser2UTCR3 = 0;
si->speed = speed;
si->tx_start = sa1100_irda_fir_tx_start;
si->irq = sa1100_irda_fir_irq;
if (si->pdata->set_speed)
si->pdata->set_speed(si->dev, speed);
sa1100_irda_rx_alloc(si);
sa1100_irda_rx_dma_start(si);
local_irq_restore(flags);
break;
default:
break;
}
return ret;
}
/*
* Control the power state of the IrDA transmitter.
* State:
* 0 - off
* 1 - short range, lowest power
* 2 - medium range, medium power
* 3 - maximum range, high power
*
* Currently, only assabet is known to support this.
*/
static int
__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state)
{
int ret = 0;
if (si->pdata->set_power)
ret = si->pdata->set_power(si->dev, state);
return ret;
}
static inline int
sa1100_set_power(struct sa1100_irda *si, unsigned int state)
{
int ret;
ret = __sa1100_irda_set_power(si, state);
if (ret == 0)
si->power = state;
return ret;
}
static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
if (IS_FIR(((struct sa1100_irda *)netdev_priv(dev))))
sa1100_irda_fir_irq(dev);
else
sa1100_irda_hpsir_irq(dev);
return IRQ_HANDLED;
}
/*
* TX DMA completion handler.
*/
static void sa1100_irda_txdma_irq(void *id)
{
struct net_device *dev = id;
struct sa1100_irda *si = netdev_priv(dev);
struct sk_buff *skb = si->txskb;
si->txskb = NULL;
/*
* Wait for the transmission to complete. Unfortunately,
* the hardware doesn't give us an interrupt to indicate
* "end of frame".
*/
do
rmb();
while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);
/*
* Clear the transmit underrun bit.
*/
Ser2HSSR0 = HSSR0_TUR;
/*
* Do we need to change speed? Note that we're lazy
* here - we don't free the old rxskb. We don't need
* to allocate a buffer either.
*/
if (si->newspeed) {
sa1100_irda_set_speed(si, si->newspeed);
si->newspeed = 0;
}
/*
* Start reception. This disables the transmitter for
* us. This will be using the existing RX buffer.
*/
sa1100_irda_rx_dma_start(si);
/*
* Account and free the packet.
*/
if (skb) {
dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE);
dev->stats.tx_packets ++;
dev->stats.tx_bytes += skb->len;
dev_kfree_skb_irq(skb);
}
/*
* Make sure that the TX queue is available for sending
* (for retries). TX has priority over RX at all times.
*/
netif_wake_queue(dev);
return si->irq(dev, si);
}
static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
......@@ -660,62 +668,19 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
if (speed != si->speed && speed != -1)
si->newspeed = speed;
/*
* If this is an empty frame, we can bypass a lot.
*/
/* If this is an empty frame, we can bypass a lot. */
if (skb->len == 0) {
if (si->newspeed) {
si->newspeed = 0;
sa1100_irda_set_speed(si, speed);
}
sa1100_irda_check_speed(si);
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
if (!IS_FIR(si)) {
netif_stop_queue(dev);
si->tx_buff.data = si->tx_buff.head;
si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data,
si->tx_buff.truesize);
/*
* Set the transmit interrupt enable. This will fire
* off an interrupt immediately. Note that we disable
* the receiver so we won't get spurious characteres
* received.
*/
Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE;
dev_kfree_skb(skb);
} else {
int mtt = irda_get_mtt(skb);
/*
* We must not be transmitting...
*/
BUG_ON(si->txskb);
netif_stop_queue(dev);
si->txskb = skb;
si->txbuf_dma = dma_map_single(si->dev, skb->data,
skb->len, DMA_TO_DEVICE);
/* We must not already have a skb to transmit... */
BUG_ON(si->dma_tx.skb);
sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len);
/*
* If we have a mean turn-around time, impose the specified
* specified delay. We could shorten this by timing from
* the point we received the packet.
*/
if (mtt)
udelay(mtt);
Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE;
}
return NETDEV_TX_OK;
return si->tx_start(skb, dev, si);
}
static int
......@@ -762,6 +727,69 @@ sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
return ret;
}
static int sa1100_irda_startup(struct sa1100_irda *si)
{
int ret;
/*
* Ensure that the ports for this device are setup correctly.
*/
if (si->pdata->startup) {
ret = si->pdata->startup(si->dev);
if (ret)
return ret;
}
/*
* Configure PPC for IRDA - we want to drive TXD2 low.
* We also want to drive this pin low during sleep.
*/
PPSR &= ~PPC_TXD2;
PSDR &= ~PPC_TXD2;
PPDR |= PPC_TXD2;
/*
* Enable HP-SIR modulation, and ensure that the port is disabled.
*/
Ser2UTCR3 = 0;
Ser2HSCR0 = HSCR0_UART;
Ser2UTCR4 = si->utcr4;
Ser2UTCR0 = UTCR0_8BitData;
Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL;
/*
* Clear status register
*/
Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
ret = sa1100_irda_set_speed(si, si->speed = 9600);
if (ret) {
Ser2UTCR3 = 0;
Ser2HSCR0 = 0;
if (si->pdata->shutdown)
si->pdata->shutdown(si->dev);
}
return ret;
}
static void sa1100_irda_shutdown(struct sa1100_irda *si)
{
/*
* Stop all DMA activity.
*/
dmaengine_terminate_all(si->dma_rx.chan);
dmaengine_terminate_all(si->dma_tx.chan);
/* Disable the port. */
Ser2UTCR3 = 0;
Ser2HSCR0 = 0;
if (si->pdata->shutdown)
si->pdata->shutdown(si->dev);
}
static int sa1100_irda_start(struct net_device *dev)
{
struct sa1100_irda *si = netdev_priv(dev);
......@@ -769,25 +797,16 @@ static int sa1100_irda_start(struct net_device *dev)
si->speed = 9600;
err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
if (err)
goto err_irq;
err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive",
NULL, NULL, &si->rxdma);
err = sa1100_irda_dma_request(si->dev, &si->dma_rx, "Ser2ICPRc",
&sa1100_irda_fir_rx);
if (err)
goto err_rx_dma;
err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit",
sa1100_irda_txdma_irq, dev, &si->txdma);
err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr",
&sa1100_irda_sir_tx);
if (err)
goto err_tx_dma;
/*
* The interrupt must remain disabled for now.
*/
disable_irq(dev->irq);
/*
* Setup the serial port for the specified speed.
*/
......@@ -803,44 +822,60 @@ static int sa1100_irda_start(struct net_device *dev)
if (!si->irlap)
goto err_irlap;
err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
if (err)
goto err_irq;
/*
* Now enable the interrupt and start the queue
*/
si->open = 1;
sa1100_set_power(si, power_level); /* low power mode */
enable_irq(dev->irq);
netif_start_queue(dev);
return 0;
err_irq:
irlap_close(si->irlap);
err_irlap:
si->open = 0;
sa1100_irda_shutdown(si);
err_startup:
sa1100_free_dma(si->txdma);
dma_release_channel(si->dma_tx.chan);
err_tx_dma:
sa1100_free_dma(si->rxdma);
dma_release_channel(si->dma_rx.chan);
err_rx_dma:
free_irq(dev->irq, dev);
err_irq:
return err;
}
static int sa1100_irda_stop(struct net_device *dev)
{
struct sa1100_irda *si = netdev_priv(dev);
struct sk_buff *skb;
disable_irq(dev->irq);
netif_stop_queue(dev);
si->open = 0;
sa1100_irda_shutdown(si);
/*
* If we have been doing DMA receive, make sure we
* If we have been doing any DMA activity, make sure we
* tidy that up cleanly.
*/
if (si->rxskb) {
dma_unmap_single(si->dev, si->rxbuf_dma, HPSIR_MAX_RXLEN,
skb = si->dma_rx.skb;
if (skb) {
dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1,
DMA_FROM_DEVICE);
dev_kfree_skb(si->rxskb);
si->rxskb = NULL;
dev_kfree_skb(skb);
si->dma_rx.skb = NULL;
}
skb = si->dma_tx.skb;
if (skb) {
dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
DMA_TO_DEVICE);
dev_kfree_skb(skb);
si->dma_tx.skb = NULL;
}
/* Stop IrLAP */
......@@ -849,14 +884,11 @@ static int sa1100_irda_stop(struct net_device *dev)
si->irlap = NULL;
}
netif_stop_queue(dev);
si->open = 0;
/*
* Free resources
*/
sa1100_free_dma(si->txdma);
sa1100_free_dma(si->rxdma);
dma_release_channel(si->dma_tx.chan);
dma_release_channel(si->dma_rx.chan);
free_irq(dev->irq, dev);
sa1100_set_power(si, 0);
......@@ -888,11 +920,15 @@ static int sa1100_irda_probe(struct platform_device *pdev)
struct net_device *dev;
struct sa1100_irda *si;
unsigned int baudrate_mask;
int err;
int err, irq;
if (!pdev->dev.platform_data)
return -EINVAL;
irq = platform_get_irq(pdev, 0);
if (irq <= 0)
return irq < 0 ? irq : -ENXIO;
err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY;
if (err)
goto err_mem_1;
......@@ -907,22 +943,27 @@ static int sa1100_irda_probe(struct platform_device *pdev)
if (!dev)
goto err_mem_4;
SET_NETDEV_DEV(dev, &pdev->dev);
si = netdev_priv(dev);
si->dev = &pdev->dev;
si->pdata = pdev->dev.platform_data;
sg_init_table(&si->dma_rx.sg, 1);
sg_init_table(&si->dma_tx.sg, 1);
/*
* Initialise the HP-SIR buffers
*/
err = sa1100_irda_init_iobuf(&si->rx_buff, 14384);
if (err)
goto err_mem_5;
err = sa1100_irda_init_iobuf(&si->tx_buff, 4000);
err = sa1100_irda_init_iobuf(&si->tx_buff, IRDA_SIR_MAX_FRAME);
if (err)
goto err_mem_5;
dev->netdev_ops = &sa1100_irda_netdev_ops;
dev->irq = IRQ_Ser2ICP;
dev->irq = irq;
irda_init_max_qos_capabilies(&si->qos);
......@@ -996,6 +1037,74 @@ static int sa1100_irda_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
/*
* Suspend the IrDA interface.
*/
static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sa1100_irda *si;
if (!dev)
return 0;
si = netdev_priv(dev);
if (si->open) {
/*
* Stop the transmit queue
*/
netif_device_detach(dev);
disable_irq(dev->irq);
sa1100_irda_shutdown(si);
__sa1100_irda_set_power(si, 0);
}
return 0;
}
/*
* Resume the IrDA interface.
*/
static int sa1100_irda_resume(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sa1100_irda *si;
if (!dev)
return 0;
si = netdev_priv(dev);
if (si->open) {
/*
* If we missed a speed change, initialise at the new speed
* directly. It is debatable whether this is actually
* required, but in the interests of continuing from where
* we left off it is desirable. The converse argument is
* that we should re-negotiate at 9600 baud again.
*/
if (si->newspeed) {
si->speed = si->newspeed;
si->newspeed = 0;
}
sa1100_irda_startup(si);
__sa1100_irda_set_power(si, si->power);
enable_irq(dev->irq);
/*
* This automatically wakes up the queue
*/
netif_device_attach(dev);
}
return 0;
}
#else
#define sa1100_irda_suspend NULL
#define sa1100_irda_resume NULL
#endif
static struct platform_driver sa1100ir_driver = {
.probe = sa1100_irda_probe,
.remove = sa1100_irda_remove,
......
......@@ -94,12 +94,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta
ret = sa1111_pcmcia_configure_socket(skt, state);
if (ret == 0) {
unsigned long flags;
local_irq_save(flags);
NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set;
local_irq_restore(flags);
neponset_ncr_frob(ncr_mask, ncr_set);
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
}
......
......@@ -22,6 +22,40 @@
#include "sa1111_generic.h"
/*
* These are offsets from the above base.
*/
#define PCCR 0x0000
#define PCSSR 0x0004
#define PCSR 0x0008
#define PCSR_S0_READY (1<<0)
#define PCSR_S1_READY (1<<1)
#define PCSR_S0_DETECT (1<<2)
#define PCSR_S1_DETECT (1<<3)
#define PCSR_S0_VS1 (1<<4)
#define PCSR_S0_VS2 (1<<5)
#define PCSR_S1_VS1 (1<<6)
#define PCSR_S1_VS2 (1<<7)
#define PCSR_S0_WP (1<<8)
#define PCSR_S1_WP (1<<9)
#define PCSR_S0_BVD1 (1<<10)
#define PCSR_S0_BVD2 (1<<11)
#define PCSR_S1_BVD1 (1<<12)
#define PCSR_S1_BVD2 (1<<13)
#define PCCR_S0_RST (1<<0)
#define PCCR_S1_RST (1<<1)
#define PCCR_S0_FLT (1<<2)
#define PCCR_S1_FLT (1<<3)
#define PCCR_S0_PWAITEN (1<<4)
#define PCCR_S1_PWAITEN (1<<5)
#define PCCR_S0_PSE (1<<6)
#define PCCR_S1_PSE (1<<7)
#define PCSSR_S0_SLEEP (1<<0)
#define PCSSR_S1_SLEEP (1<<1)
#define IDX_IRQ_S0_READY_NINT (0)
#define IDX_IRQ_S0_CD_VALID (1)
#define IDX_IRQ_S0_BVD1_STSCHG (2)
......@@ -49,7 +83,7 @@ static void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
{
struct sa1111_pcmcia_socket *s = to_skt(skt);
unsigned long status = sa1111_readl(s->dev->mapbase + SA1111_PCSR);
unsigned long status = sa1111_readl(s->dev->mapbase + PCSR);
switch (skt->nr) {
case 0:
......@@ -105,10 +139,10 @@ int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT;
local_irq_save(flags);
val = sa1111_readl(s->dev->mapbase + SA1111_PCCR);
val = sa1111_readl(s->dev->mapbase + PCCR);
val &= ~pccr_skt_mask;
val |= pccr_set_mask & pccr_skt_mask;
sa1111_writel(val, s->dev->mapbase + SA1111_PCCR);
sa1111_writel(val, s->dev->mapbase + PCCR);
local_irq_restore(flags);
return 0;
......@@ -163,12 +197,18 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
static int pcmcia_probe(struct sa1111_dev *dev)
{
void __iomem *base;
int ret;
ret = sa1111_enable_device(dev);
if (ret)
return ret;
dev_set_drvdata(&dev->dev, NULL);
if (!request_mem_region(dev->res.start, 512,
SA1111_DRIVER_NAME(dev)))
if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) {
sa1111_disable_device(dev);
return -EBUSY;
}
base = dev->mapbase;
......@@ -181,8 +221,8 @@ static int pcmcia_probe(struct sa1111_dev *dev)
/*
* Initialise the suspend state.
*/
sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR);
sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR);
sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + PCSSR);
sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + PCCR);
#ifdef CONFIG_SA1100_BADGE4
pcmcia_badge4_init(&dev->dev);
......@@ -212,6 +252,7 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev)
}
release_mem_region(dev->res.start, 512);
sa1111_disable_device(dev);
return 0;
}
......
......@@ -32,7 +32,7 @@
#include <linux/bitops.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <mach/irqs.h>
#ifdef CONFIG_ARCH_PXA
#include <mach/regs-rtc.h>
......
......@@ -38,6 +38,7 @@
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <asm/mach/serial_sa1100.h>
/* We've been assigned a range on the "Low-density serial ports" major */
......
......@@ -16,29 +16,115 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <mach/assabet.h>
#include <mach/badge4.h>
#include <asm/hardware/sa1111.h>
#ifndef CONFIG_SA1111
#error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined."
#endif
extern int usb_disabled(void);
#define USB_STATUS 0x0118
#define USB_RESET 0x011c
#define USB_IRQTEST 0x0120
#define USB_RESET_FORCEIFRESET (1 << 0)
#define USB_RESET_FORCEHCRESET (1 << 1)
#define USB_RESET_CLKGENRESET (1 << 2)
#define USB_RESET_SIMSCALEDOWN (1 << 3)
#define USB_RESET_USBINTTEST (1 << 4)
#define USB_RESET_SLEEPSTBYEN (1 << 5)
#define USB_RESET_PWRSENSELOW (1 << 6)
#define USB_RESET_PWRCTRLLOW (1 << 7)
#define USB_STATUS_IRQHCIRMTWKUP (1 << 7)
#define USB_STATUS_IRQHCIBUFFACC (1 << 8)
#define USB_STATUS_NIRQHCIM (1 << 9)
#define USB_STATUS_NHCIMFCLR (1 << 10)
#define USB_STATUS_USBPWRSENSE (1 << 11)
/*-------------------------------------------------------------------------*/
#if 0
static void dump_hci_status(struct usb_hcd *hcd, const char *label)
{
unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
dbg("%s USB_STATUS = { %s%s%s%s%s}", label,
((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
}
#endif
static void sa1111_start_hc(struct sa1111_dev *dev)
static int ohci_sa1111_reset(struct usb_hcd *hcd)
{
unsigned int usb_rst = 0;
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
return ohci_init(ohci);
}
printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
__FILE__);
static int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int ret;
#ifdef CONFIG_SA1100_BADGE4
if (machine_is_badge4()) {
badge4_set_5V(BADGE4_5V_USB, 1);
ret = ohci_run(ohci);
if (ret < 0) {
ohci_err(ohci, "can't start\n");
ohci_stop(hcd);
}
return ret;
}
static const struct hc_driver ohci_sa1111_hc_driver = {
.description = hcd_name,
.product_desc = "SA-1111 OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),
/*
* generic hardware linkage
*/
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
*/
.reset = ohci_sa1111_reset,
.start = ohci_sa1111_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 sa1111_start_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst = 0;
int ret;
dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n");
if (machine_is_xp860() ||
machine_has_neponset() ||
......@@ -51,220 +137,121 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
* host controller in reset.
*/
sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
dev->mapbase + SA1111_USB_RESET);
dev->mapbase + USB_RESET);
/*
* Now, carefully enable the USB clock, and take
* the USB host controller out of reset.
*/
sa1111_enable_device(dev);
ret = sa1111_enable_device(dev);
if (ret == 0) {
udelay(11);
sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
sa1111_writel(usb_rst, dev->mapbase + USB_RESET);
}
return ret;
}
static void sa1111_stop_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst;
printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n",
__FILE__);
dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n");
/*
* Put the USB host controller into reset.
*/
usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
usb_rst = sa1111_readl(dev->mapbase + USB_RESET);
sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
dev->mapbase + SA1111_USB_RESET);
dev->mapbase + USB_RESET);
/*
* Stop the USB clock.
*/
sa1111_disable_device(dev);
#ifdef CONFIG_SA1100_BADGE4
if (machine_is_badge4()) {
/* Disable power to the USB bus */
badge4_set_5V(BADGE4_5V_USB, 0);
}
#endif
}
/*-------------------------------------------------------------------------*/
#if 0
static void dump_hci_status(struct usb_hcd *hcd, const char *label)
{
unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
}
#endif
/*-------------------------------------------------------------------------*/
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
/**
* usb_hcd_sa1111_probe - initialize SA-1111-based HCDs
* Context: !in_interrupt()
* ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs
*
* 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.
*
* Store this function in the HCD's struct pci_driver as probe().
* then invokes the start() method for the HCD associated with it.
*/
int usb_hcd_sa1111_probe (const struct hc_driver *driver,
struct sa1111_dev *dev)
static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
{
struct usb_hcd *hcd;
int retval;
int ret;
hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
if (usb_disabled())
return -ENODEV;
hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111");
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = dev->res.start;
hcd->rsrc_len = resource_size(&dev->res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
dbg("request_mem_region failed");
retval = -EBUSY;
ret = -EBUSY;
goto err1;
}
hcd->regs = dev->mapbase;
sa1111_start_hc(dev);
ohci_hcd_init(hcd_to_ohci(hcd));
ret = sa1111_start_hc(dev);
if (ret)
goto err2;
retval = usb_add_hcd(hcd, dev->irq[1], 0);
if (retval == 0)
return retval;
ret = usb_add_hcd(hcd, dev->irq[1], 0);
if (ret == 0)
return ret;
sa1111_stop_hc(dev);
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
return retval;
return ret;
}
/* may be called without controller electrically present */
/* may be called with controller, bus, and devices active */
/**
* usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
* ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
* @dev: USB Host Controller being removed
* Context: !in_interrupt()
*
* Reverses the effect of usb_hcd_sa1111_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
*
* Reverses the effect of ohci_hcd_sa1111_probe(), first invoking
* the HCD's stop() method.
*/
void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
{
struct usb_hcd *hcd = sa1111_get_drvdata(dev);
usb_remove_hcd(hcd);
sa1111_stop_hc(dev);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
}
/*-------------------------------------------------------------------------*/
static int __devinit
ohci_sa1111_start (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
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_sa1111_hc_driver = {
.description = hcd_name,
.product_desc = "SA-1111 OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),
/*
* generic hardware linkage
*/
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
*/
.start = ohci_sa1111_start,
.stop = ohci_stop,
/*
* 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_sa1111_drv_probe(struct sa1111_dev *dev)
{
int ret;
if (usb_disabled())
return -ENODEV;
ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev);
return ret;
}
static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev)
static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev)
{
struct usb_hcd *hcd = sa1111_get_drvdata(dev);
usb_hcd_sa1111_remove(hcd, dev);
return 0;
if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
hcd->driver->shutdown(hcd);
sa1111_stop_hc(dev);
}
}
static struct sa1111_driver ohci_hcd_sa1111_driver = {
.drv = {
.name = "sa1111-ohci",
.owner = THIS_MODULE,
},
.devid = SA1111_DEVID_USB,
.probe = ohci_hcd_sa1111_drv_probe,
.remove = ohci_hcd_sa1111_drv_remove,
.probe = ohci_hcd_sa1111_probe,
.remove = ohci_hcd_sa1111_remove,
.shutdown = ohci_hcd_sa1111_shutdown,
};
......@@ -173,281 +173,47 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/cpufreq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <video/sa1100fb.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <mach/assabet.h>
#include <mach/shannon.h>
/*
* debugging?
*/
#define DEBUG 0
/*
* Complain if VAR is out of range.
*/
#define DEBUG_VAR 1
#undef ASSABET_PAL_VIDEO
#include "sa1100fb.h"
extern void (*sa1100fb_backlight_power)(int on);
extern void (*sa1100fb_lcd_power)(int on);
static struct sa1100fb_rgb rgb_4 = {
static const struct sa1100fb_rgb rgb_4 = {
.red = { .offset = 0, .length = 4, },
.green = { .offset = 0, .length = 4, },
.blue = { .offset = 0, .length = 4, },
.transp = { .offset = 0, .length = 0, },
};
static struct sa1100fb_rgb rgb_8 = {
static const struct sa1100fb_rgb rgb_8 = {
.red = { .offset = 0, .length = 8, },
.green = { .offset = 0, .length = 8, },
.blue = { .offset = 0, .length = 8, },
.transp = { .offset = 0, .length = 0, },
};
static struct sa1100fb_rgb def_rgb_16 = {
static const struct sa1100fb_rgb def_rgb_16 = {
.red = { .offset = 11, .length = 5, },
.green = { .offset = 5, .length = 6, },
.blue = { .offset = 0, .length = 5, },
.transp = { .offset = 0, .length = 0, },
};
#ifdef CONFIG_SA1100_ASSABET
#ifndef ASSABET_PAL_VIDEO
/*
* The assabet uses a sharp LQ039Q2DS54 LCD module. It is actually
* takes an RGB666 signal, but we provide it with an RGB565 signal
* instead (def_rgb_16).
*/
static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
.pixclock = 171521, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 5, .vsync_len = 1,
.left_margin = 61, .upper_margin = 3,
.right_margin = 9, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
};
#else
static struct sa1100fb_mach_info pal_info __initdata = {
.pixclock = 67797, .bpp = 16,
.xres = 640, .yres = 512,
.hsync_len = 64, .vsync_len = 6,
.left_margin = 125, .upper_margin = 70,
.right_margin = 115, .lower_margin = 36,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
};
#endif
#endif
#ifdef CONFIG_SA1100_H3600
static struct sa1100fb_mach_info h3600_info __initdata = {
.pixclock = 174757, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 3, .vsync_len = 3,
.left_margin = 12, .upper_margin = 10,
.right_margin = 17, .lower_margin = 1,
.cmap_static = 1,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
};
static struct sa1100fb_rgb h3600_rgb_16 = {
.red = { .offset = 12, .length = 4, },
.green = { .offset = 7, .length = 4, },
.blue = { .offset = 1, .length = 4, },
.transp = { .offset = 0, .length = 0, },
};
#endif
#ifdef CONFIG_SA1100_H3100
static struct sa1100fb_mach_info h3100_info __initdata = {
.pixclock = 406977, .bpp = 4,
.xres = 320, .yres = 240,
.hsync_len = 26, .vsync_len = 41,
.left_margin = 4, .upper_margin = 0,
.right_margin = 4, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.cmap_greyscale = 1,
.cmap_inverse = 1,
.lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
};
#endif
#ifdef CONFIG_SA1100_COLLIE
static struct sa1100fb_mach_info collie_info __initdata = {
.pixclock = 171521, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 5, .vsync_len = 1,
.left_margin = 11, .upper_margin = 2,
.right_margin = 30, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
};
#endif
#ifdef LART_GREY_LCD
static struct sa1100fb_mach_info lart_grey_info __initdata = {
.pixclock = 150000, .bpp = 4,
.xres = 320, .yres = 240,
.hsync_len = 1, .vsync_len = 1,
.left_margin = 4, .upper_margin = 0,
.right_margin = 2, .lower_margin = 0,
.cmap_greyscale = 1,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
};
#endif
#ifdef LART_COLOR_LCD
static struct sa1100fb_mach_info lart_color_info __initdata = {
.pixclock = 150000, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 2, .vsync_len = 3,
.left_margin = 69, .upper_margin = 14,
.right_margin = 8, .lower_margin = 4,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
};
#endif
#ifdef LART_VIDEO_OUT
static struct sa1100fb_mach_info lart_video_info __initdata = {
.pixclock = 39721, .bpp = 16,
.xres = 640, .yres = 480,
.hsync_len = 95, .vsync_len = 2,
.left_margin = 40, .upper_margin = 32,
.right_margin = 24, .lower_margin = 11,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
};
#endif
#ifdef LART_KIT01_LCD
static struct sa1100fb_mach_info lart_kit01_info __initdata = {
.pixclock = 63291, .bpp = 16,
.xres = 640, .yres = 480,
.hsync_len = 64, .vsync_len = 3,
.left_margin = 122, .upper_margin = 45,
.right_margin = 10, .lower_margin = 10,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg
};
#endif
#ifdef CONFIG_SA1100_SHANNON
static struct sa1100fb_mach_info shannon_info __initdata = {
.pixclock = 152500, .bpp = 8,
.xres = 640, .yres = 480,
.hsync_len = 4, .vsync_len = 3,
.left_margin = 2, .upper_margin = 0,
.right_margin = 1, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
.lccr3 = LCCR3_ACBsDiv(512),
};
#endif
static struct sa1100fb_mach_info * __init
sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
{
struct sa1100fb_mach_info *inf = NULL;
/*
* R G B T
* default {11,5}, { 5,6}, { 0,5}, { 0,0}
* h3600 {12,4}, { 7,4}, { 1,4}, { 0,0}
* freebird { 8,4}, { 4,4}, { 0,4}, {12,4}
*/
#ifdef CONFIG_SA1100_ASSABET
if (machine_is_assabet()) {
#ifndef ASSABET_PAL_VIDEO
inf = &lq039q2ds54_info;
#else
inf = &pal_info;
#endif
}
#endif
#ifdef CONFIG_SA1100_H3100
if (machine_is_h3100()) {
inf = &h3100_info;
}
#endif
#ifdef CONFIG_SA1100_H3600
if (machine_is_h3600()) {
inf = &h3600_info;
fbi->rgb[RGB_16] = &h3600_rgb_16;
}
#endif
#ifdef CONFIG_SA1100_COLLIE
if (machine_is_collie()) {
inf = &collie_info;
}
#endif
#ifdef CONFIG_SA1100_LART
if (machine_is_lart()) {
#ifdef LART_GREY_LCD
inf = &lart_grey_info;
#endif
#ifdef LART_COLOR_LCD
inf = &lart_color_info;
#endif
#ifdef LART_VIDEO_OUT
inf = &lart_video_info;
#endif
#ifdef LART_KIT01_LCD
inf = &lart_kit01_info;
#endif
}
#endif
#ifdef CONFIG_SA1100_SHANNON
if (machine_is_shannon()) {
inf = &shannon_info;
}
#endif
return inf;
}
static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
......@@ -533,7 +299,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* is what you poke into the framebuffer to produce the
* colour you requested.
*/
if (fbi->cmap_inverse) {
if (fbi->inf->cmap_inverse) {
red = 0xffff - red;
green = 0xffff - green;
blue = 0xffff - blue;
......@@ -607,14 +373,14 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->xres = MIN_XRES;
if (var->yres < MIN_YRES)
var->yres = MIN_YRES;
if (var->xres > fbi->max_xres)
var->xres = fbi->max_xres;
if (var->yres > fbi->max_yres)
var->yres = fbi->max_yres;
if (var->xres > fbi->inf->xres)
var->xres = fbi->inf->xres;
if (var->yres > fbi->inf->yres)
var->yres = fbi->inf->yres;
var->xres_virtual = max(var->xres_virtual, var->xres);
var->yres_virtual = max(var->yres_virtual, var->yres);
DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
dev_dbg(fbi->dev, "var->bits_per_pixel=%d\n", var->bits_per_pixel);
switch (var->bits_per_pixel) {
case 4:
rgbidx = RGB_4;
......@@ -638,16 +404,16 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->blue = fbi->rgb[rgbidx]->blue;
var->transp = fbi->rgb[rgbidx]->transp;
DPRINTK("RGBT length = %d:%d:%d:%d\n",
dev_dbg(fbi->dev, "RGBT length = %d:%d:%d:%d\n",
var->red.length, var->green.length, var->blue.length,
var->transp.length);
DPRINTK("RGBT offset = %d:%d:%d:%d\n",
dev_dbg(fbi->dev, "RGBT offset = %d:%d:%d:%d\n",
var->red.offset, var->green.offset, var->blue.offset,
var->transp.offset);
#ifdef CONFIG_CPU_FREQ
printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
dev_dbg(fbi->dev, "dma period = %d ps, clock = %d kHz\n",
sa1100fb_display_dma_period(var),
cpufreq_get(smp_processor_id()));
#endif
......@@ -655,22 +421,10 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
return 0;
}
static inline void sa1100fb_set_truecolor(u_int is_true_color)
static void sa1100fb_set_visual(struct sa1100fb_info *fbi, u32 visual)
{
if (machine_is_assabet()) {
#if 1 // phase 4 or newer Assabet's
if (is_true_color)
ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
else
ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
#else
// older Assabet's
if (is_true_color)
ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
else
ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
#endif
}
if (fbi->inf->set_visual)
fbi->inf->set_visual(visual);
}
/*
......@@ -683,11 +437,11 @@ static int sa1100fb_set_par(struct fb_info *info)
struct fb_var_screeninfo *var = &info->var;
unsigned long palette_mem_size;
DPRINTK("set_par\n");
dev_dbg(fbi->dev, "set_par\n");
if (var->bits_per_pixel == 16)
fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
else if (!fbi->cmap_static)
else if (!fbi->inf->cmap_static)
fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
else {
/*
......@@ -704,7 +458,7 @@ static int sa1100fb_set_par(struct fb_info *info)
palette_mem_size = fbi->palette_size * sizeof(u16);
DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
dev_dbg(fbi->dev, "palette_mem_size = 0x%08lx\n", palette_mem_size);
fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
......@@ -712,7 +466,7 @@ static int sa1100fb_set_par(struct fb_info *info)
/*
* Set (any) board control register to handle new color depth
*/
sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
sa1100fb_set_visual(fbi, fbi->fb.fix.visual);
sa1100fb_activate_var(var, fbi);
return 0;
......@@ -728,7 +482,7 @@ sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
/*
* Make sure the user isn't doing something stupid.
*/
if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static))
if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->inf->cmap_static))
return -EINVAL;
return gen_set_cmap(cmap, kspc, con, info);
......@@ -775,7 +529,7 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
int i;
DPRINTK("sa1100fb_blank: blank=%d\n", blank);
dev_dbg(fbi->dev, "sa1100fb_blank: blank=%d\n", blank);
switch (blank) {
case FB_BLANK_POWERDOWN:
......@@ -863,43 +617,43 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
u_int half_screen_size, yres, pcd;
u_long flags;
DPRINTK("Configuring SA1100 LCD\n");
dev_dbg(fbi->dev, "Configuring SA1100 LCD\n");
DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
dev_dbg(fbi->dev, "var: xres=%d hslen=%d lm=%d rm=%d\n",
var->xres, var->hsync_len,
var->left_margin, var->right_margin);
DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
dev_dbg(fbi->dev, "var: yres=%d vslen=%d um=%d bm=%d\n",
var->yres, var->vsync_len,
var->upper_margin, var->lower_margin);
#if DEBUG_VAR
if (var->xres < 16 || var->xres > 1024)
printk(KERN_ERR "%s: invalid xres %d\n",
dev_err(fbi->dev, "%s: invalid xres %d\n",
fbi->fb.fix.id, var->xres);
if (var->hsync_len < 1 || var->hsync_len > 64)
printk(KERN_ERR "%s: invalid hsync_len %d\n",
dev_err(fbi->dev, "%s: invalid hsync_len %d\n",
fbi->fb.fix.id, var->hsync_len);
if (var->left_margin < 1 || var->left_margin > 255)
printk(KERN_ERR "%s: invalid left_margin %d\n",
dev_err(fbi->dev, "%s: invalid left_margin %d\n",
fbi->fb.fix.id, var->left_margin);
if (var->right_margin < 1 || var->right_margin > 255)
printk(KERN_ERR "%s: invalid right_margin %d\n",
dev_err(fbi->dev, "%s: invalid right_margin %d\n",
fbi->fb.fix.id, var->right_margin);
if (var->yres < 1 || var->yres > 1024)
printk(KERN_ERR "%s: invalid yres %d\n",
dev_err(fbi->dev, "%s: invalid yres %d\n",
fbi->fb.fix.id, var->yres);
if (var->vsync_len < 1 || var->vsync_len > 64)
printk(KERN_ERR "%s: invalid vsync_len %d\n",
dev_err(fbi->dev, "%s: invalid vsync_len %d\n",
fbi->fb.fix.id, var->vsync_len);
if (var->upper_margin < 0 || var->upper_margin > 255)
printk(KERN_ERR "%s: invalid upper_margin %d\n",
dev_err(fbi->dev, "%s: invalid upper_margin %d\n",
fbi->fb.fix.id, var->upper_margin);
if (var->lower_margin < 0 || var->lower_margin > 255)
printk(KERN_ERR "%s: invalid lower_margin %d\n",
dev_err(fbi->dev, "%s: invalid lower_margin %d\n",
fbi->fb.fix.id, var->lower_margin);
#endif
new_regs.lccr0 = fbi->lccr0 |
new_regs.lccr0 = fbi->inf->lccr0 |
LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
......@@ -914,7 +668,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
* the YRES parameter.
*/
yres = var->yres;
if (fbi->lccr0 & LCCR0_Dual)
if (fbi->inf->lccr0 & LCCR0_Dual)
yres /= 2;
new_regs.lccr2 =
......@@ -924,14 +678,14 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
LCCR2_EndFrmDel(var->lower_margin);
pcd = get_pcd(var->pixclock, cpufreq_get(0));
new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 |
new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0);
DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1);
DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2);
DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3);
dev_dbg(fbi->dev, "nlccr0 = 0x%08lx\n", new_regs.lccr0);
dev_dbg(fbi->dev, "nlccr1 = 0x%08lx\n", new_regs.lccr1);
dev_dbg(fbi->dev, "nlccr2 = 0x%08lx\n", new_regs.lccr2);
dev_dbg(fbi->dev, "nlccr3 = 0x%08lx\n", new_regs.lccr3);
half_screen_size = var->bits_per_pixel;
half_screen_size = half_screen_size * var->xres * var->yres / 16;
......@@ -951,9 +705,12 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
* Only update the registers if the controller is enabled
* and something has changed.
*/
if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) ||
(LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) ||
(DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
if (readl_relaxed(fbi->base + LCCR0) != fbi->reg_lccr0 ||
readl_relaxed(fbi->base + LCCR1) != fbi->reg_lccr1 ||
readl_relaxed(fbi->base + LCCR2) != fbi->reg_lccr2 ||
readl_relaxed(fbi->base + LCCR3) != fbi->reg_lccr3 ||
readl_relaxed(fbi->base + DBAR1) != fbi->dbar1 ||
readl_relaxed(fbi->base + DBAR2) != fbi->dbar2)
sa1100fb_schedule_work(fbi, C_REENABLE);
return 0;
......@@ -967,18 +724,18 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
*/
static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
{
DPRINTK("backlight o%s\n", on ? "n" : "ff");
dev_dbg(fbi->dev, "backlight o%s\n", on ? "n" : "ff");
if (sa1100fb_backlight_power)
sa1100fb_backlight_power(on);
if (fbi->inf->backlight_power)
fbi->inf->backlight_power(on);
}
static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
{
DPRINTK("LCD power o%s\n", on ? "n" : "ff");
dev_dbg(fbi->dev, "LCD power o%s\n", on ? "n" : "ff");
if (sa1100fb_lcd_power)
sa1100fb_lcd_power(on);
if (fbi->inf->lcd_power)
fbi->inf->lcd_power(on);
}
static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
......@@ -1008,14 +765,25 @@ static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
}
if (mask) {
unsigned long flags;
/*
* SA-1100 requires the GPIO direction register set
* appropriately for the alternate function. Hence
* we set it here via bitmask rather than excessive
* fiddling via the GPIO subsystem - and even then
* we'll still have to deal with GAFR.
*/
local_irq_save(flags);
GPDR |= mask;
GAFR |= mask;
local_irq_restore(flags);
}
}
static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
{
DPRINTK("Enabling LCD controller\n");
dev_dbg(fbi->dev, "Enabling LCD controller\n");
/*
* Make sure the mode bits are present in the first palette entry
......@@ -1024,43 +792,46 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
/* Sequence from 11.7.10 */
LCCR3 = fbi->reg_lccr3;
LCCR2 = fbi->reg_lccr2;
LCCR1 = fbi->reg_lccr1;
LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
DBAR1 = fbi->dbar1;
DBAR2 = fbi->dbar2;
LCCR0 |= LCCR0_LEN;
if (machine_is_shannon()) {
GPDR |= SHANNON_GPIO_DISP_EN;
GPSR |= SHANNON_GPIO_DISP_EN;
}
DPRINTK("DBAR1 = 0x%08x\n", DBAR1);
DPRINTK("DBAR2 = 0x%08x\n", DBAR2);
DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);
writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);
writel_relaxed(fbi->reg_lccr1, fbi->base + LCCR1);
writel_relaxed(fbi->reg_lccr0 & ~LCCR0_LEN, fbi->base + LCCR0);
writel_relaxed(fbi->dbar1, fbi->base + DBAR1);
writel_relaxed(fbi->dbar2, fbi->base + DBAR2);
writel_relaxed(fbi->reg_lccr0 | LCCR0_LEN, fbi->base + LCCR0);
if (machine_is_shannon())
gpio_set_value(SHANNON_GPIO_DISP_EN, 1);
dev_dbg(fbi->dev, "DBAR1: 0x%08x\n", readl_relaxed(fbi->base + DBAR1));
dev_dbg(fbi->dev, "DBAR2: 0x%08x\n", readl_relaxed(fbi->base + DBAR2));
dev_dbg(fbi->dev, "LCCR0: 0x%08x\n", readl_relaxed(fbi->base + LCCR0));
dev_dbg(fbi->dev, "LCCR1: 0x%08x\n", readl_relaxed(fbi->base + LCCR1));
dev_dbg(fbi->dev, "LCCR2: 0x%08x\n", readl_relaxed(fbi->base + LCCR2));
dev_dbg(fbi->dev, "LCCR3: 0x%08x\n", readl_relaxed(fbi->base + LCCR3));
}
static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
{
DECLARE_WAITQUEUE(wait, current);
u32 lccr0;
DPRINTK("Disabling LCD controller\n");
dev_dbg(fbi->dev, "Disabling LCD controller\n");
if (machine_is_shannon()) {
GPCR |= SHANNON_GPIO_DISP_EN;
}
if (machine_is_shannon())
gpio_set_value(SHANNON_GPIO_DISP_EN, 0);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&fbi->ctrlr_wait, &wait);
LCSR = 0xffffffff; /* Clear LCD Status Register */
LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */
LCCR0 &= ~LCCR0_LEN; /* Disable LCD Controller */
/* Clear LCD Status Register */
writel_relaxed(~0, fbi->base + LCSR);
lccr0 = readl_relaxed(fbi->base + LCCR0);
lccr0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */
writel_relaxed(lccr0, fbi->base + LCCR0);
lccr0 &= ~LCCR0_LEN; /* Disable LCD Controller */
writel_relaxed(lccr0, fbi->base + LCCR0);
schedule_timeout(20 * HZ / 1000);
remove_wait_queue(&fbi->ctrlr_wait, &wait);
......@@ -1072,14 +843,15 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
{
struct sa1100fb_info *fbi = dev_id;
unsigned int lcsr = LCSR;
unsigned int lcsr = readl_relaxed(fbi->base + LCSR);
if (lcsr & LCSR_LDD) {
LCCR0 |= LCCR0_LDM;
u32 lccr0 = readl_relaxed(fbi->base + LCCR0) | LCCR0_LDM;
writel_relaxed(lccr0, fbi->base + LCCR0);
wake_up(&fbi->ctrlr_wait);
}
LCSR = lcsr;
writel_relaxed(lcsr, fbi->base + LCSR);
return IRQ_HANDLED;
}
......@@ -1268,7 +1040,7 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
switch (val) {
case CPUFREQ_ADJUST:
case CPUFREQ_INCOMPATIBLE:
printk(KERN_DEBUG "min dma period: %d ps, "
dev_dbg(fbi->dev, "min dma period: %d ps, "
"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
policy->max);
/* todo: fill in min/max values */
......@@ -1318,7 +1090,7 @@ static int sa1100fb_resume(struct platform_device *dev)
* cache. Once this area is remapped, all virtual memory
* access to the video memory should occur at the new region.
*/
static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
static int __devinit sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
{
/*
* We reserve one page for the palette, plus the size
......@@ -1344,7 +1116,7 @@ static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
}
/* Fake monspecs to fill in fbinfo structure */
static struct fb_monspecs monspecs __initdata = {
static struct fb_monspecs monspecs __devinitdata = {
.hfmin = 30000,
.hfmax = 70000,
.vfmin = 50,
......@@ -1352,10 +1124,11 @@ static struct fb_monspecs monspecs __initdata = {
};
static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
{
struct sa1100fb_mach_info *inf;
struct sa1100fb_mach_info *inf = dev->platform_data;
struct sa1100fb_info *fbi;
unsigned i;
fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
GFP_KERNEL);
......@@ -1390,8 +1163,6 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
fbi->rgb[RGB_8] = &rgb_8;
fbi->rgb[RGB_16] = &def_rgb_16;
inf = sa1100fb_get_machine_info(fbi);
/*
* People just don't seem to get this. We don't support
* anything but correct entries now, so panic if someone
......@@ -1402,13 +1173,10 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
panic("sa1100fb error: invalid LCCR3 fields set or zero "
"pixclock.");
fbi->max_xres = inf->xres;
fbi->fb.var.xres = inf->xres;
fbi->fb.var.xres_virtual = inf->xres;
fbi->max_yres = inf->yres;
fbi->fb.var.yres = inf->yres;
fbi->fb.var.yres_virtual = inf->yres;
fbi->max_bpp = inf->bpp;
fbi->fb.var.bits_per_pixel = inf->bpp;
fbi->fb.var.pixclock = inf->pixclock;
fbi->fb.var.hsync_len = inf->hsync_len;
......@@ -1419,14 +1187,16 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
fbi->fb.var.lower_margin = inf->lower_margin;
fbi->fb.var.sync = inf->sync;
fbi->fb.var.grayscale = inf->cmap_greyscale;
fbi->cmap_inverse = inf->cmap_inverse;
fbi->cmap_static = inf->cmap_static;
fbi->lccr0 = inf->lccr0;
fbi->lccr3 = inf->lccr3;
fbi->state = C_STARTUP;
fbi->task_state = (u_char)-1;
fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
fbi->max_bpp / 8;
fbi->fb.fix.smem_len = inf->xres * inf->yres *
inf->bpp / 8;
fbi->inf = inf;
/* Copy the RGB bitfield overrides */
for (i = 0; i < NR_RGB; i++)
if (inf->rgb[i])
fbi->rgb[i] = inf->rgb[i];
init_waitqueue_head(&fbi->ctrlr_wait);
INIT_WORK(&fbi->task, sa1100fb_task);
......@@ -1438,13 +1208,20 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
static int __devinit sa1100fb_probe(struct platform_device *pdev)
{
struct sa1100fb_info *fbi;
struct resource *res;
int ret, irq;
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "no platform LCD data\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
if (irq < 0 || !res)
return -EINVAL;
if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
if (!request_mem_region(res->start, resource_size(res), "LCD"))
return -EBUSY;
fbi = sa1100fb_init_fbinfo(&pdev->dev);
......@@ -1452,6 +1229,10 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
if (!fbi)
goto failed;
fbi->base = ioremap(res->start, resource_size(res));
if (!fbi->base)
goto failed;
/* Initialize video memory */
ret = sa1100fb_map_video_memory(fbi);
if (ret)
......@@ -1459,14 +1240,16 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
if (ret) {
printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
goto failed;
}
#ifdef ASSABET_PAL_VIDEO
if (machine_is_assabet())
ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
#endif
if (machine_is_shannon()) {
ret = gpio_request_one(SHANNON_GPIO_DISP_EN,
GPIOF_OUT_INIT_LOW, "display enable");
if (ret)
goto err_free_irq;
}
/*
* This makes sure that our colour bitfield
......@@ -1478,7 +1261,7 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
ret = register_framebuffer(&fbi->fb);
if (ret < 0)
goto err_free_irq;
goto err_reg_fb;
#ifdef CONFIG_CPU_FREQ
fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
......@@ -1490,12 +1273,17 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
/* This driver cannot be unloaded at the moment */
return 0;
err_reg_fb:
if (machine_is_shannon())
gpio_free(SHANNON_GPIO_DISP_EN);
err_free_irq:
free_irq(irq, fbi);
failed:
if (fbi)
iounmap(fbi->base);
platform_set_drvdata(pdev, NULL);
kfree(fbi);
release_mem_region(0xb0100000, 0x10000);
release_mem_region(res->start, resource_size(res));
return ret;
}
......@@ -1505,6 +1293,7 @@ static struct platform_driver sa1100fb_driver = {
.resume = sa1100fb_resume,
.driver = {
.name = "sa11x0-fb",
.owner = THIS_MODULE,
},
};
......
......@@ -10,44 +10,15 @@
* for more details.
*/
/*
* These are the bitfields for each
* display depth that we support.
*/
struct sa1100fb_rgb {
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp;
};
/*
* This structure describes the machine which we are running on.
*/
struct sa1100fb_mach_info {
u_long pixclock;
u_short xres;
u_short yres;
u_char bpp;
u_char hsync_len;
u_char left_margin;
u_char right_margin;
u_char vsync_len;
u_char upper_margin;
u_char lower_margin;
u_char sync;
u_int cmap_greyscale:1,
cmap_inverse:1,
cmap_static:1,
unused:29;
u_int lccr0;
u_int lccr3;
};
#define LCCR0 0x0000 /* LCD Control Reg. 0 */
#define LCSR 0x0004 /* LCD Status Reg. */
#define DBAR1 0x0010 /* LCD DMA Base Address Reg. channel 1 */
#define DCAR1 0x0014 /* LCD DMA Current Address Reg. channel 1 */
#define DBAR2 0x0018 /* LCD DMA Base Address Reg. channel 2 */
#define DCAR2 0x001C /* LCD DMA Current Address Reg. channel 2 */
#define LCCR1 0x0020 /* LCD Control Reg. 1 */
#define LCCR2 0x0024 /* LCD Control Reg. 2 */
#define LCCR3 0x0028 /* LCD Control Reg. 3 */
/* Shadows for LCD controller registers */
struct sa1100fb_lcd_reg {
......@@ -57,19 +28,11 @@ struct sa1100fb_lcd_reg {
unsigned long lccr3;
};
#define RGB_4 (0)
#define RGB_8 (1)
#define RGB_16 (2)
#define NR_RGB 3
struct sa1100fb_info {
struct fb_info fb;
struct device *dev;
struct sa1100fb_rgb *rgb[NR_RGB];
u_int max_bpp;
u_int max_xres;
u_int max_yres;
const struct sa1100fb_rgb *rgb[NR_RGB];
void __iomem *base;
/*
* These are the addresses we mapped
......@@ -88,12 +51,6 @@ struct sa1100fb_info {
dma_addr_t dbar1;
dma_addr_t dbar2;
u_int lccr0;
u_int lccr3;
u_int cmap_inverse:1,
cmap_static:1,
unused:30;
u_int reg_lccr0;
u_int reg_lccr1;
u_int reg_lccr2;
......@@ -109,6 +66,8 @@ struct sa1100fb_info {
struct notifier_block freq_transition;
struct notifier_block freq_policy;
#endif
const struct sa1100fb_mach_info *inf;
};
#define TO_INF(ptr,member) container_of(ptr,struct sa1100fb_info,member)
......@@ -129,15 +88,6 @@ struct sa1100fb_info {
#define SA1100_NAME "SA1100"
/*
* Debug macros
*/
#if DEBUG
# define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ## args)
#else
# define DPRINTK(fmt, args...)
#endif
/*
* Minimum X and Y resolutions
*/
......
......@@ -10,8 +10,6 @@
#ifndef MCP_H
#define MCP_H
#include <mach/dma.h>
struct mcp_ops;
struct mcp {
......@@ -21,12 +19,7 @@ struct mcp {
int use_count;
unsigned int sclk_rate;
unsigned int rw_timeout;
dma_device_t dma_audio_rd;
dma_device_t dma_audio_wr;
dma_device_t dma_telco_rd;
dma_device_t dma_telco_wr;
struct device attached_device;
int gpio_base;
};
struct mcp_ops {
......@@ -47,15 +40,14 @@ void mcp_disable(struct mcp *);
#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
struct mcp *mcp_host_alloc(struct device *, size_t);
int mcp_host_register(struct mcp *);
void mcp_host_unregister(struct mcp *);
int mcp_host_add(struct mcp *, void *);
void mcp_host_del(struct mcp *);
void mcp_host_free(struct mcp *);
struct mcp_driver {
struct device_driver drv;
int (*probe)(struct mcp *);
void (*remove)(struct mcp *);
int (*suspend)(struct mcp *, pm_message_t);
int (*resume)(struct mcp *);
};
int mcp_driver_register(struct mcp_driver *);
......
......@@ -12,7 +12,7 @@
#include <linux/mfd/mcp.h>
#include <linux/gpio.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#define UCB_IO_DATA 0x00
#define UCB_IO_DIR 0x01
......@@ -104,17 +104,27 @@
#define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
#define UCB_MODE_AUD_OFF_CAN (1 << 13)
enum ucb1x00_reset {
UCB_RST_PROBE,
UCB_RST_RESUME,
UCB_RST_SUSPEND,
UCB_RST_REMOVE,
UCB_RST_PROBE_FAIL,
};
struct ucb1x00_irq {
void *devid;
void (*fn)(int, void *);
struct ucb1x00_plat_data {
void (*reset)(enum ucb1x00_reset);
unsigned irq_base;
int gpio_base;
unsigned can_wakeup;
};
struct ucb1x00 {
spinlock_t lock;
raw_spinlock_t irq_lock;
struct mcp *mcp;
unsigned int irq;
struct semaphore adc_sem;
int irq_base;
struct mutex adc_mutex;
spinlock_t io_lock;
u16 id;
u16 io_dir;
......@@ -122,7 +132,8 @@ struct ucb1x00 {
u16 adc_cr;
u16 irq_fal_enbl;
u16 irq_ris_enbl;
struct ucb1x00_irq irq_handler[16];
u16 irq_mask;
u16 irq_wake;
struct device dev;
struct list_head node;
struct list_head devs;
......@@ -144,7 +155,7 @@ struct ucb1x00_driver {
struct list_head devs;
int (*add)(struct ucb1x00_dev *dev);
void (*remove)(struct ucb1x00_dev *dev);
int (*suspend)(struct ucb1x00_dev *dev, pm_message_t state);
int (*suspend)(struct ucb1x00_dev *dev);
int (*resume)(struct ucb1x00_dev *dev);
};
......@@ -245,15 +256,4 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
void ucb1x00_adc_enable(struct ucb1x00 *ucb);
void ucb1x00_adc_disable(struct ucb1x00 *ucb);
/*
* Which edges of the IRQ do you want to control today?
*/
#define UCB_RISING (1 << 0)
#define UCB_FALLING (1 << 1)
int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
#endif
/*
* SA11x0 DMA Engine support
*
* Copyright (C) 2012 Russell King
*
* 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.
*/
#ifndef __LINUX_SA11X0_DMA_H
#define __LINUX_SA11X0_DMA_H
struct dma_chan;
#if defined(CONFIG_DMA_SA11X0) || defined(CONFIG_DMA_SA11X0_MODULE)
bool sa11x0_dma_filter_fn(struct dma_chan *, void *);
#else
static inline bool sa11x0_dma_filter_fn(struct dma_chan *c, void *d)
{
return false;
}
#endif
#endif
/*
* StrongARM 1100 LCD Controller Frame Buffer Device
*
* Copyright (C) 1999 Eric A. Thomas
* Based on acornfb.c Copyright (C) Russell King.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#ifndef _VIDEO_SA1100FB_H
#define _VIDEO_SA1100FB_H
#include <linux/fb.h>
#include <linux/types.h>
#define RGB_4 0
#define RGB_8 1
#define RGB_16 2
#define NR_RGB 3
/* These are the bitfields for each display depth that we support. */
struct sa1100fb_rgb {
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp;
};
/* This structure describes the machine which we are running on. */
struct sa1100fb_mach_info {
u_long pixclock;
u_short xres;
u_short yres;
u_char bpp;
u_char hsync_len;
u_char left_margin;
u_char right_margin;
u_char vsync_len;
u_char upper_margin;
u_char lower_margin;
u_char sync;
u_int cmap_greyscale:1,
cmap_inverse:1,
cmap_static:1,
unused:29;
u_int lccr0;
u_int lccr3;
/* Overrides for the default RGB maps */
const struct sa1100fb_rgb *rgb[NR_RGB];
void (*backlight_power)(int);
void (*lcd_power)(int);
void (*set_visual)(u32);
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment