#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/hardware/sa1111.h>
-#include "sa1111.h"
+/*
+ * We keep the following data for the overall SA1111. Note that the
+ * struct device and struct resource are "fake"; they should be supplied
+ * by the bus above us. However, in the interests of getting all SA1111
+ * drivers converted over to the device model, we provide this as an
+ * anchor point for all the other drivers.
+ */
+struct sa1111 {
+ struct device dev;
+ struct resource res;
+ int irq;
+ spinlock_t lock;
+ void *base;
+};
+
+/*
+ * We _really_ need to eliminate this. Its only users
+ * are the PWM and DMA checking code.
+ */
+static struct sa1111 *g_sa1111;
+
+static struct sa1111_dev usb_dev = {
+ .dev = {
+ .name = "Intel Corporation SA1111 [USB Controller]",
+ },
+ .skpcr_mask = SKPCR_UCLKEN,
+ .devid = SA1111_DEVID_USB,
+ .irq = {
+ USBPWR
+ NIRQHCIM,
+ HCIBUFFACC,
+ HCIRMTWKP,
+ NHCIMFCIR,
+ USB_PORT_RESUME
+ },
+};
+
+static struct sa1111_dev sac_dev = {
+ .dev = {
+ .name = "Intel Corporation SA1111 [Audio Controller]",
+ },
+ .skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
+ .devid = SA1111_DEVID_SAC,
+ .irq = {
+ AUDXMTDMADONEA,
+ AUDXMTDMADONEB,
+ AUDRCVDMADONEA,
+ AUDRCVDMADONEB
+ },
+};
+
+static struct sa1111_dev ssp_dev = {
+ .dev = {
+ .name = "Intel Corporation SA1111 [SSP Controller]",
+ },
+ .skpcr_mask = SKPCR_SCLKEN,
+ .devid = SA1111_DEVID_SSP,
+};
+
+static struct sa1111_dev kbd_dev = {
+ .dev = {
+ .name = "Intel Corporation SA1111 [PS2]",
+ },
+ .skpcr_mask = SKPCR_PTCLKEN,
+ .devid = SA1111_DEVID_PS2,
+ .irq = {
+ IRQ_TPRXINT,
+ IRQ_TPTXINT
+ },
+};
+
+static struct sa1111_dev mse_dev = {
+ .dev = {
+ .name = "Intel Corporation SA1111 [PS2]",
+ },
+ .skpcr_mask = SKPCR_PMCLKEN,
+ .devid = SA1111_DEVID_PS2,
+ .irq = {
+ IRQ_MSRXINT,
+ IRQ_MSTXINT
+ },
+};
+
+static struct sa1111_dev int_dev = {
+ .dev = {
+ .name = "Intel Corporation SA1111 [Interrupt Controller]",
+ },
+ .skpcr_mask = 0,
+ .devid = SA1111_DEVID_INT,
+};
-struct sa1111_device *sa1111;
+static struct sa1111_dev pcmcia_dev = {
+ .dev = {
+ .name = "Intel Corporation SA1111 [PCMCIA Controller]",
+ },
+ .skpcr_mask = 0,
+ .devid = SA1111_DEVID_PCMCIA,
+ .irq = {
+ S0_READY_NINT,
+ S0_CD_VALID,
+ S0_BVD1_STSCHG,
+ S1_READY_NINT,
+ S1_CD_VALID,
+ S1_BVD1_STSCHG,
+ },
+};
-EXPORT_SYMBOL(sa1111);
+static struct sa1111_dev *devs[] = {
+ &usb_dev,
+ &sac_dev,
+ &ssp_dev,
+ &kbd_dev,
+ &mse_dev,
+ &int_dev,
+ &pcmcia_dev,
+};
+
+static unsigned int dev_offset[] = {
+ SA1111_USB,
+ 0x0600,
+ 0x0800,
+ SA1111_KBD,
+ SA1111_MSE,
+ SA1111_INTC,
+ 0x1800,
+};
/*
* SA1111 interrupt support. Since clearing an IRQ while there are
.type = sa1111_type_highirq,
};
-static void __init sa1111_init_irq(int irq_nr)
+static void __init sa1111_init_irq(struct sa1111_dev *sadev)
{
unsigned int irq;
- request_mem_region(_INTTEST0, 512, "irqs");
+ /*
+ * We're guaranteed that this region hasn't been taken.
+ */
+ request_mem_region(sadev->res.start, 512, "irqs");
/* disable all IRQs */
- INTEN0 = 0;
- INTEN1 = 0;
+ sa1111_writel(0, sadev->mapbase + SA1111_INTEN0);
+ sa1111_writel(0, sadev->mapbase + SA1111_INTEN1);
+ sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN0);
+ sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN1);
/*
* detect on rising edge. Note: Feb 2001 Errata for SA1111
* specifies that S0ReadyInt and S1ReadyInt should be '1'.
*/
- INTPOL0 = 0;
- INTPOL1 = SA1111_IRQMASK_HI(S0_READY_NINT) |
- SA1111_IRQMASK_HI(S1_READY_NINT);
+ sa1111_writel(0, sadev->mapbase + SA1111_INTPOL0);
+ sa1111_writel(SA1111_IRQMASK_HI(S0_READY_NINT) |
+ SA1111_IRQMASK_HI(S1_READY_NINT),
+ sadev->mapbase + SA1111_INTPOL1);
/* clear all IRQs */
- INTSTATCLR0 = ~0;
- INTSTATCLR1 = ~0;
+ sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR0);
+ sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR1);
for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
set_irq_chip(irq, &sa1111_low_chip);
/*
* Register SA1111 interrupt
*/
- set_irq_type(irq_nr, IRQT_RISING);
- set_irq_chained_handler(irq_nr, sa1111_irq_handler);
+ set_irq_type(sadev->irq[0], IRQT_RISING);
+ set_irq_chained_handler(sadev->irq[0], sa1111_irq_handler);
}
-static int sa1111_suspend(struct device *dev, u32 state, u32 level)
-{
- return 0;
-}
-
-static int sa1111_resume(struct device *dev, u32 level)
-{
- return 0;
-}
-
-static struct device_driver sa1111_device_driver = {
- .suspend = sa1111_suspend,
- .resume = sa1111_resume,
-};
+static struct device_driver sa1111_device_driver;
/**
* sa1111_probe - probe for a single SA1111 chip.
* %0 successful.
*/
static int __init
-sa1111_probe(struct device *parent, unsigned long phys_addr)
+sa1111_probe(unsigned long phys_addr, int irq)
{
- struct sa1111_device *sa;
+ struct sa1111 *sachip;
unsigned long id;
- int ret = -ENODEV;
+ unsigned int has_devs;
+ int i, ret = -ENODEV;
- sa = kmalloc(sizeof(struct sa1111_device), GFP_KERNEL);
- if (!sa)
+ sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL);
+ if (!sachip)
return -ENOMEM;
- memset(sa, 0, sizeof(struct sa1111_device));
+ memset(sachip, 0, sizeof(struct sa1111));
+
+ spin_lock_init(&sachip->lock);
+
+ strncpy(sachip->dev.name, "Intel Corporation SA1111", sizeof(sachip->dev.name));
+ snprintf(sachip->dev.bus_id, sizeof(sachip->dev.bus_id), "%8.8lx", phys_addr);
+ sachip->dev.driver = &sa1111_device_driver;
+ sachip->dev.driver_data = sachip;
- sa->resource.name = "SA1111";
- sa->resource.start = phys_addr;
- sa->resource.end = phys_addr + 0x2000;
+ sachip->res.name = sachip->dev.name;
+ sachip->res.start = phys_addr;
+ sachip->res.end = phys_addr + 0x2000;
+ sachip->irq = irq;
- if (request_resource(&iomem_resource, &sa->resource)) {
+ if (request_resource(&iomem_resource, &sachip->res)) {
ret = -EBUSY;
goto out;
}
- /* eventually ioremap... */
- sa->base = (void *)0xf4000000;
- if (!sa->base) {
+ sachip->base = ioremap(phys_addr, PAGE_SIZE * 2);
+ if (!sachip->base) {
ret = -ENOMEM;
goto release;
}
/*
* Probe for the chip. Only touch the SBI registers.
*/
- id = sa1111_readl(sa->base + SA1111_SKID);
+ id = sa1111_readl(sachip->base + SA1111_SKID);
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
ret = -ENODEV;
/*
* We found the chip.
*/
- strcpy(sa->dev.name, "SA1111");
- sprintf(sa->dev.bus_id, "%8.8lx", phys_addr);
- sa->dev.parent = parent;
- sa->dev.driver = &sa1111_device_driver;
-
- ret = device_register(&sa->dev);
+ ret = register_sys_device(&sachip->dev);
if (ret)
printk("sa1111 device_register failed: %d\n", ret);
"silicon revision %lx, metal revision %lx\n",
(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
- sa1111 = sa;
+ 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);
+
+ for (i = 0; i < ARRAY_SIZE(devs); i++) {
+ if (!(has_devs & (1 << i)))
+ continue;
+
+ snprintf(devs[i]->dev.bus_id, sizeof(devs[i]->dev.bus_id),
+ "%4.4x", dev_offset[i]);
+
+ devs[i]->dev.parent = &sachip->dev;
+ devs[i]->dev.bus = &sa1111_bus_type;
+ devs[i]->res.start = sachip->res.start + dev_offset[i];
+ devs[i]->res.end = devs[i]->res.start + 511;
+ devs[i]->res.name = devs[i]->dev.name;
+ devs[i]->res.flags = IORESOURCE_MEM;
+ devs[i]->mapbase = sachip->base + dev_offset[i];
+
+ if (request_resource(&sachip->res, &devs[i]->res)) {
+ printk("SA1111: failed to allocate resource for %s\n",
+ devs[i]->res.name);
+ continue;
+ }
+
+ device_register(&devs[i]->dev);
+ }
return 0;
unmap:
-// iounmap(sa->base);
+ iounmap(sachip->base);
release:
- release_resource(&sa->resource);
+ release_resource(&sachip->res);
out:
- kfree(sa);
+ kfree(sachip);
return ret;
}
+static void __sa1111_remove(struct sa1111 *sachip)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(devs); i++) {
+ put_device(&devs[i]->dev);
+ release_resource(&devs[i]->res);
+ }
+
+ iounmap(sachip->base);
+ release_resource(&sachip->res);
+ kfree(sachip);
+}
+
/*
* Bring the SA1111 out of reset. This requires a set procedure:
* 1. nRESET asserted (by hardware)
* SBI_SMCR
* SBI_SKID
*/
-void sa1111_wake(void)
+static void sa1111_wake(struct sa1111 *sachip)
{
- struct sa1111_device *sa = sa1111;
unsigned long flags, r;
- local_irq_save(flags);
+ spin_lock_irqsave(&sachip->lock, flags);
/*
* First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
/*
* Turn VCO on, and disable PLL Bypass.
*/
- r = sa1111_readl(sa->base + SA1111_SKCR);
+ r = sa1111_readl(sachip->base + SA1111_SKCR);
r &= ~SKCR_VCO_OFF;
- sa1111_writel(r, sa->base + SA1111_SKCR);
+ sa1111_writel(r, sachip->base + SA1111_SKCR);
r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
- sa1111_writel(r, sa->base + SA1111_SKCR);
+ sa1111_writel(r, sachip->base + SA1111_SKCR);
/*
* Wait lock time. SA1111 manual _doesn't_
* Enable RCLK. We also ensure that RDYEN is set.
*/
r |= SKCR_RCLKEN | SKCR_RDYEN;
- sa1111_writel(r, sa->base + SA1111_SKCR);
+ sa1111_writel(r, sachip->base + SA1111_SKCR);
/*
* Wait 14 RCLK cycles for the chip to finish coming out
/*
* Ensure all clocks are initially off.
*/
- sa1111_writel(0, sa->base + SA1111_SKPCR);
+ sa1111_writel(0, sachip->base + SA1111_SKPCR);
- local_irq_restore(flags);
-}
-
-void sa1111_doze(void)
-{
- struct sa1111_device *sa = sa1111;
- unsigned long flags;
- unsigned int val;
-
- local_irq_save(flags);
-
- if (sa1111_readl(sa->base + SA1111_SKPCR) & SKPCR_UCLKEN) {
- local_irq_restore(flags);
- printk("SA1111 doze mode refused\n");
- return;
- }
-
- val = sa1111_readl(sa->base + SA1111_SKCR);
- sa1111_writel(val & ~SKCR_RCLKEN, sa->base + SA1111_SKCR);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&sachip->lock, flags);
}
/*
* Configure the SA1111 shared memory controller.
*/
-void sa1111_configure_smc(int sdram, unsigned int drac, unsigned int cas_latency)
+void
+sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
+ unsigned int cas_latency)
{
- struct sa1111_device *sa = sa1111;
unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC);
if (cas_latency == 3)
smcr |= SMCR_CLAT;
- sa1111_writel(smcr, sa->base + SA1111_SMCR);
-}
-
-EXPORT_SYMBOL(sa1111_wake);
-EXPORT_SYMBOL(sa1111_doze);
-
-void sa1111_enable_device(unsigned int mask)
-{
- struct sa1111_device *sa = sa1111;
- unsigned int val;
-
- preempt_disable();
- val = sa1111_readl(sa->base + SA1111_SKPCR);
- sa1111_writel(val | mask, sa->base + SA1111_SKPCR);
- preempt_enable();
+ sa1111_writel(smcr, sachip->base + SA1111_SMCR);
}
-void sa1111_disable_device(unsigned int mask)
-{
- struct sa1111_device *sa = sa1111;
- unsigned int val;
-
- preempt_disable();
- val = sa1111_readl(sa->base + SA1111_SKPCR);
- sa1111_writel(val & ~mask, sa->base + SA1111_SKPCR);
- preempt_enable();
-}
-
-EXPORT_SYMBOL(sa1111_enable_device);
-EXPORT_SYMBOL(sa1111_disable_device);
-
-/* According to the "Intel StrongARM SA-1111 Microprocessor Companion
+/*
+ * According to the "Intel StrongARM SA-1111 Microprocessor Companion
* Chip Specification Update" (June 2000), erratum #7, there is a
- * significant bug in Serial Audio Controller DMA. If the SAC is
- * accessing a region of memory above 1MB relative to the bank base,
+ * 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.
*/
int sa1111_check_dma_bug(dma_addr_t addr)
{
- unsigned int physaddr=SA1111_DMA_ADDR((unsigned int)addr);
+ struct sa1111 *sachip = g_sa1111;
+ unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr);
+ unsigned int smcr;
/* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
* User's Guide" mentions that jumpers R51 and R52 control the
* above the start of the target bank:
*/
if (physaddr<(1<<20))
- return 0;
+ return 0;
- switch (FExtr(SBI_SMCR, SMCR_DRAC)) {
+ smcr = sa1111_readl(sachip->base + SA1111_SMCR);
+ switch (FExtr(smcr, SMCR_DRAC)) {
case 01: /* 10 row + bank address bits, A<20> must not be set */
if (physaddr & (1<<20))
return -1;
break;
default:
printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n",
- __FUNCTION__, FExtr(SBI_SMCR, SMCR_DRAC));
+ __FUNCTION__, FExtr(smcr, SMCR_DRAC));
return -1;
}
return 0;
}
-EXPORT_SYMBOL(sa1111_check_dma_bug);
-
int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
{
+ unsigned int val;
int ret;
- ret = sa1111_probe(parent, phys);
+ ret = sa1111_probe(phys, irq);
if (ret < 0)
return ret;
/*
* We found it. Wake the chip up.
*/
- sa1111_wake();
+ sa1111_wake(g_sa1111);
/*
* The SDRAM configuration of the SA1110 and the SA1111 must
* MBGNT signal, so we must have called sa1110_mb_disable()
* beforehand.
*/
- sa1111_configure_smc(1,
+ sa1111_configure_smc(g_sa1111, 1,
FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
* We only need to turn on DCLK whenever we want to use the
* DMA. It can otherwise be held firmly in the off position.
*/
- sa1111_enable_device(SKPCR_DCLKEN);
+ val = sa1111_readl(g_sa1111->base + SA1111_SKPCR);
+ sa1111_writel(val | SKPCR_DCLKEN, g_sa1111->base + SA1111_SKPCR);
/*
* Enable the SA1110 memory bus request and grant signals.
/*
* Initialise SA1111 IRQs
*/
- sa1111_init_irq(irq);
+ int_dev.irq[0] = irq;
+ sa1111_init_irq(&int_dev);
+
+ return 0;
+}
+
+struct sa1111_save_data {
+ unsigned int skcr;
+ unsigned int skpcr;
+ unsigned int skcdr;
+ unsigned char skaud;
+ unsigned char skpwm0;
+ unsigned char skpwm1;
+
+ /*
+ * Interrupt controller
+ */
+ unsigned int intpol0;
+ unsigned int intpol1;
+ unsigned int inten0;
+ unsigned int inten1;
+ unsigned int wakepol0;
+ unsigned int wakepol1;
+ unsigned int wakeen0;
+ unsigned int wakeen1;
+};
+
+static int sa1111_suspend(struct device *dev, u32 state, u32 level)
+{
+ struct sa1111 *sachip = dev->driver_data;
+ unsigned long flags;
+ char *base;
+
+ /*
+ * Save state.
+ */
+ if (level == SUSPEND_SAVE_STATE ||
+ level == SUSPEND_DISABLE ||
+ level == SUSPEND_POWER_DOWN) {
+ struct sa1111_save_data *save;
+
+ if (!dev->saved_state)
+ dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
+ if (!dev->saved_state)
+ return -ENOMEM;
+
+ save = (struct sa1111_save_data *)dev->saved_state;
+
+ spin_lock_irqsave(&sachip->lock, flags);
+ base = sachip->base;
+ save->skcr = sa1111_readl(base + SA1111_SKCR);
+ save->skpcr = sa1111_readl(base + SA1111_SKPCR);
+ save->skcdr = sa1111_readl(base + SA1111_SKCDR);
+ save->skaud = sa1111_readl(base + SA1111_SKAUD);
+ save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0);
+ save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1);
+
+ base = sachip->base + SA1111_INTC;
+ save->intpol0 = sa1111_readl(base + SA1111_INTPOL0);
+ save->intpol1 = sa1111_readl(base + SA1111_INTPOL1);
+ save->inten0 = sa1111_readl(base + SA1111_INTEN0);
+ save->inten1 = sa1111_readl(base + SA1111_INTEN1);
+ save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0);
+ save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1);
+ save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0);
+ save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1);
+ spin_unlock_irqrestore(&sachip->lock, flags);
+ }
+
+ /*
+ * Disable.
+ */
+ if (level == SUSPEND_DISABLE && state == 4) {
+ unsigned int val;
+
+ spin_lock_irqsave(&sachip->lock, flags);
+ base = sachip->base;
+
+ sa1111_writel(0, base + SA1111_SKPWM0);
+ sa1111_writel(0, base + SA1111_SKPWM1);
+ val = sa1111_readl(base + SA1111_SKCR);
+ sa1111_writel(val | SKCR_SLEEP, base + SA1111_SKCR);
+
+ spin_unlock_irqrestore(&sachip->lock, flags);
+ }
+
+ return 0;
+}
+
+/*
+ * sa1111_resume - Restore the SA1111 device state.
+ * @dev: device to restore
+ * @level: resume level
+ *
+ * Restore the general state of the SA1111; clock control and
+ * interrupt controller. Other parts of the SA1111 must be
+ * restored by their respective drivers, and must be called
+ * via LDM after this function.
+ */
+static int sa1111_resume(struct device *dev, u32 level)
+{
+ struct sa1111 *sachip = dev->driver_data;
+ struct sa1111_save_data *save;
+ unsigned long flags, id;
+ char *base;
+
+ if (level != RESUME_RESTORE_STATE && level != RESUME_ENABLE)
+ return 0;
+
+ save = (struct sa1111_save_data *)dev->saved_state;
+ if (!save)
+ return 0;
+
+ dev->saved_state = NULL;
+
+ /*
+ * Ensure that the SA1111 is still here.
+ */
+ id = sa1111_readl(sachip->base + SA1111_SKID);
+ if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
+ __sa1111_remove(sachip);
+ kfree(save);
+ return 0;
+ }
+
+ spin_lock_irqsave(&sachip->lock, flags);
+ sa1111_wake(sachip);
+
+ base = sachip->base;
+ sa1111_writel(save->skcr, base + SA1111_SKCR);
+ sa1111_writel(save->skpcr, base + SA1111_SKPCR);
+ sa1111_writel(save->skcdr, base + SA1111_SKCDR);
+ sa1111_writel(save->skaud, base + SA1111_SKAUD);
+ sa1111_writel(save->skpwm0, base + SA1111_SKPWM0);
+ sa1111_writel(save->skpwm1, base + SA1111_SKPWM1);
+
+ base = sachip->base + SA1111_INTC;
+ sa1111_writel(save->intpol0, base + SA1111_INTPOL0);
+ sa1111_writel(save->intpol1, base + SA1111_INTPOL1);
+ sa1111_writel(save->inten0, base + SA1111_INTEN0);
+ sa1111_writel(save->inten1, base + SA1111_INTEN1);
+ sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0);
+ sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1);
+ sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0);
+ sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1);
+ spin_unlock_irqrestore(&sachip->lock, flags);
+
+ kfree(save);
return 0;
}
+
+static struct device_driver sa1111_device_driver = {
+ .suspend = sa1111_suspend,
+ .resume = sa1111_resume,
+};
+
+/*
+ * Get the parent device driver (us) structure
+ * from a child function device
+ */
+static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev)
+{
+ return (struct sa1111 *)sadev->dev.parent->driver_data;
+}
+
+/*
+ * The bits in the opdiv field are non-linear.
+ */
+static unsigned char opdiv_table[] = { 1, 4, 2, 8 };
+
+static unsigned int __sa1111_pll_clock(struct sa1111 *sachip)
+{
+ unsigned int skcdr, fbdiv, ipdiv, opdiv;
+
+ skcdr = sa1111_readl(sachip->base + SA1111_SKCDR);
+
+ fbdiv = (skcdr & 0x007f) + 2;
+ ipdiv = ((skcdr & 0x0f80) >> 7) + 2;
+ opdiv = opdiv_table[(skcdr & 0x3000) >> 12];
+
+ return 3686400 * fbdiv / (ipdiv * opdiv);
+}
+
+/**
+ * sa1111_pll_clock - return the current PLL clock frequency.
+ * @sadev: SA1111 function block
+ *
+ * BUG: we should look at SKCR. We also blindly believe that
+ * the chip is being fed with the 3.6864MHz clock.
+ *
+ * Returns the PLL clock in Hz.
+ */
+unsigned int sa1111_pll_clock(struct sa1111_dev *sadev)
+{
+ struct sa1111 *sachip = sa1111_chip_driver(sadev);
+
+ return __sa1111_pll_clock(sachip);
+}
+
+/**
+ * sa1111_select_audio_mode - select I2S or AC link mode
+ * @sadev: SA1111 function block
+ * @mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S
+ *
+ * Frob the SKCR to select AC Link mode or I2S mode for
+ * the audio block.
+ */
+void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode)
+{
+ struct sa1111 *sachip = sa1111_chip_driver(sadev);
+ unsigned long flags;
+ unsigned int val;
+
+ spin_lock_irqsave(&sachip->lock, flags);
+
+ val = sa1111_readl(sachip->base + SA1111_SKCR);
+ if (mode == SA1111_AUDIO_I2S) {
+ val &= ~SKCR_SELAC;
+ } else {
+ val |= SKCR_SELAC;
+ }
+ sa1111_writel(val, sachip->base + SA1111_SKCR);
+
+ spin_unlock_irqrestore(&sachip->lock, flags);
+}
+
+/**
+ * sa1111_set_audio_rate - set the audio sample rate
+ * @sadev: SA1111 SAC function block
+ * @rate: sample rate to select
+ */
+int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate)
+{
+ struct sa1111 *sachip = sa1111_chip_driver(sadev);
+ unsigned int div;
+
+ if (sadev->devid != SA1111_DEVID_SAC)
+ return -EINVAL;
+
+ div = (__sa1111_pll_clock(sachip) / 256 + rate / 2) / rate;
+ if (div == 0)
+ div = 1;
+ if (div > 128)
+ div = 128;
+
+ sa1111_writel(div - 1, sachip->base + SA1111_SKAUD);
+
+ return 0;
+}
+
+/**
+ * sa1111_get_audio_rate - get the audio sample rate
+ * @sadev: SA1111 SAC function block device
+ */
+int sa1111_get_audio_rate(struct sa1111_dev *sadev)
+{
+ struct sa1111 *sachip = sa1111_chip_driver(sadev);
+ unsigned long div;
+
+ if (sadev->devid != SA1111_DEVID_SAC)
+ return -EINVAL;
+
+ div = sa1111_readl(sachip->base + SA1111_SKAUD) + 1;
+
+ return __sa1111_pll_clock(sachip) / (256 * div);
+}
+
+/*
+ * Individual device operations.
+ */
+
+/**
+ * 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)
+{
+ struct sa1111 *sachip = sa1111_chip_driver(sadev);
+ unsigned long flags;
+ unsigned int val;
+
+ 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);
+}
+
+/**
+ * sa1111_disable_device - disable an on-chip SA1111 function block
+ * @sadev: SA1111 function block device to disable
+ */
+void sa1111_disable_device(struct sa1111_dev *sadev)
+{
+ struct sa1111 *sachip = sa1111_chip_driver(sadev);
+ unsigned long flags;
+ unsigned int val;
+
+ 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);
+}
+
+/*
+ * SA1111 "Register Access Bus."
+ *
+ * We model this as a regular bus type, and hang devices directly
+ * off this.
+ */
+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;
+}
+
+struct bus_type sa1111_bus_type = {
+ .name = "RAB",
+ .match = sa1111_match,
+};
+
+static int sa1111_rab_bus_init(void)
+{
+ return bus_register(&sa1111_bus_type);
+}
+
+postcore_initcall(sa1111_rab_bus_init);
+
+EXPORT_SYMBOL(sa1111_check_dma_bug);
+EXPORT_SYMBOL(sa1111_select_audio_mode);
+EXPORT_SYMBOL(sa1111_set_audio_rate);
+EXPORT_SYMBOL(sa1111_get_audio_rate);
+EXPORT_SYMBOL(sa1111_enable_device);
+EXPORT_SYMBOL(sa1111_disable_device);
+EXPORT_SYMBOL(sa1111_pll_clock);
+EXPORT_SYMBOL(sa1111_bus_type);
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
-#include <asm/hardware/sa1111.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
+#include <asm/hardware/sa1111.h>
+
extern struct pt_regs *kbd_pt_regs;
struct ps2if {
- struct serio io;
- struct resource *res;
- unsigned long base;
- unsigned int irq;
- unsigned int skpcr_mask;
+ struct serio io;
+ struct sa1111_dev *dev;
+ unsigned long base;
+ unsigned int open;
+ spinlock_t lock;
+ unsigned int head;
+ unsigned int tail;
+ unsigned char buf[4];
};
/*
* at the most one, but we loop for safety. If there was a
* framing error, we have to manually clear the status.
*/
-static void ps2_int(int irq, void *dev_id, struct pt_regs *regs)
+static void ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
{
- struct ps2if *sa = dev_id;
+ struct ps2if *ps2if = dev_id;
unsigned int scancode, flag, status;
kbd_pt_regs = regs;
- status = sa1111_readl(sa->base + SA1111_PS2STAT);
+ status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
while (status & PS2STAT_RXF) {
if (status & PS2STAT_STP)
- sa1111_writel(PS2STAT_STP, sa->base + SA1111_PS2STAT);
+ sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT);
flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
(status & PS2STAT_RXP ? 0 : SERIO_PARITY);
- scancode = sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff;
+ scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff;
if (hweight8(scancode) & 1)
flag ^= SERIO_PARITY;
- serio_interrupt(&sa->io, scancode, flag);
+ serio_interrupt(&ps2if->io, scancode, flag);
- status = sa1111_readl(sa->base + SA1111_PS2STAT);
+ status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
}
}
+/*
+ * Completion of ps2 write
+ */
+static void ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ps2if *ps2if = dev_id;
+ unsigned int status;
+
+ spin_lock(&ps2if->lock);
+ status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+ if (ps2if->head == ps2if->tail) {
+ disable_irq(irq);
+ /* done */
+ } else if (status & PS2STAT_TXE) {
+ sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA);
+ ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
+ }
+ spin_unlock(&ps2if->lock);
+}
+
/*
* Write a byte to the PS2 port. We have to wait for the
* port to indicate that the transmitter is empty.
*/
static int ps2_write(struct serio *io, unsigned char val)
{
- struct ps2if *sa = io->driver;
- unsigned int timeleft = 10000; /* timeout in 100ms */
+ struct ps2if *ps2if = io->driver;
+ unsigned long flags;
+ unsigned int head;
- while ((sa1111_readl(sa->base + SA1111_PS2STAT) & PS2STAT_TXE) == 0 &&
- timeleft--)
- udelay(10);
+ spin_lock_irqsave(&ps2if->lock, flags);
- if (timeleft)
- sa1111_writel(val, sa->base + SA1111_PS2DATA);
+ /*
+ * 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);
+ } else {
+ if (ps2if->head == ps2if->tail)
+ enable_irq(ps2if->dev->irq[1]);
+ head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1);
+ if (head != ps2if->tail) {
+ ps2if->buf[ps2if->head] = val;
+ ps2if->head = head;
+ }
+ }
- return timeleft ? 0 : SERIO_TIMEOUT;
+ spin_unlock_irqrestore(&ps2if->lock, flags);
+ return 0;
}
static int ps2_open(struct serio *io)
{
- struct ps2if *sa = io->driver;
+ struct ps2if *ps2if = io->driver;
int ret;
- sa1111_enable_device(sa->skpcr_mask);
+ sa1111_enable_device(ps2if->dev);
- ret = request_irq(sa->irq, ps2_int, 0, "ps2", sa);
+ 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",
- sa->irq, ret);
+ ps2if->dev->irq[0], ret);
return ret;
}
- sa1111_writel(PS2CR_ENA, sa->base + SA1111_PS2CR);
+ ret = request_irq(ps2if->dev->irq[1], ps2_txint, 0,
+ SA1111_DRIVER_NAME(ps2if->dev), ps2if);
+ if (ret) {
+ printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
+ ps2if->dev->irq[1], ret);
+ free_irq(ps2if->dev->irq[0], ps2if);
+ return ret;
+ }
+ ps2if->open = 1;
+
+ sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR);
return 0;
}
static void ps2_close(struct serio *io)
{
- struct ps2if *sa = io->driver;
+ struct ps2if *ps2if = io->driver;
+
+ sa1111_writel(0, ps2if->base + SA1111_PS2CR);
- sa1111_writel(0, sa->base + SA1111_PS2CR);
+ ps2if->open = 0;
- free_irq(sa->irq, sa);
+ free_irq(ps2if->dev->irq[1], ps2if);
+ free_irq(ps2if->dev->irq[0], ps2if);
- sa1111_disable_device(sa->skpcr_mask);
+ sa1111_disable_device(ps2if->dev);
}
/*
* Clear the input buffer.
*/
-static void __init ps2_clear_input(struct ps2if *sa)
+static void __init ps2_clear_input(struct ps2if *ps2if)
{
int maxread = 100;
while (maxread--) {
- if ((sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff) == 0xff)
+ if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff)
break;
}
}
static inline unsigned int
-ps2_test_one(struct ps2if *sa, unsigned int mask)
+ps2_test_one(struct ps2if *ps2if, unsigned int mask)
{
unsigned int val;
- sa1111_writel(PS2CR_ENA | mask, sa->base + SA1111_PS2CR);
+ sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR);
udelay(2);
- val = sa1111_readl(sa->base + SA1111_PS2STAT);
+ val = sa1111_readl(ps2if->base + SA1111_PS2STAT);
return val & (PS2STAT_KBC | PS2STAT_KBD);
}
* Test the keyboard interface. We basically check to make sure that
* we can drive each line to the keyboard independently of each other.
*/
-static int __init ps2_test(struct ps2if *sa)
+static int __init ps2_test(struct ps2if *ps2if)
{
unsigned int stat;
int ret = 0;
- stat = ps2_test_one(sa, PS2CR_FKC);
+ stat = ps2_test_one(ps2if, PS2CR_FKC);
if (stat != PS2STAT_KBD) {
- printk("Keyboard interface test failed[1]: %02x\n", stat);
+ printk("PS/2 interface test failed[1]: %02x\n", stat);
ret = -ENODEV;
}
- stat = ps2_test_one(sa, 0);
+ stat = ps2_test_one(ps2if, 0);
if (stat != (PS2STAT_KBC | PS2STAT_KBD)) {
- printk("Keyboard interface test failed[2]: %02x\n", stat);
+ printk("PS/2 interface test failed[2]: %02x\n", stat);
ret = -ENODEV;
}
- stat = ps2_test_one(sa, PS2CR_FKD);
+ stat = ps2_test_one(ps2if, PS2CR_FKD);
if (stat != PS2STAT_KBC) {
- printk("Keyboard interface test failed[3]: %02x\n", stat);
+ printk("PS/2 interface test failed[3]: %02x\n", stat);
ret = -ENODEV;
}
- sa1111_writel(0, sa->base + SA1111_PS2CR);
+ sa1111_writel(0, ps2if->base + SA1111_PS2CR);
return ret;
}
/*
- * Initialise one PS/2 port.
+ * Add one device to this driver.
*/
-static int __init ps2_init_one(struct sa1111_device *dev, struct ps2if *sa)
+static int ps2_probe(struct device *dev)
{
+ struct sa1111_dev *sadev = SA1111_DEV(dev);
+ struct ps2if *ps2if;
int ret;
+ ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL);
+ if (!ps2if) {
+ return -ENOMEM;
+ }
+
+ memset(ps2if, 0, sizeof(struct ps2if));
+
+ ps2if->io.type = SERIO_8042;
+ ps2if->io.write = ps2_write;
+ ps2if->io.open = ps2_open;
+ ps2if->io.close = ps2_close;
+ ps2if->io.name = dev->name;
+ ps2if->io.phys = dev->bus_id;
+ ps2if->io.driver = ps2if;
+ ps2if->dev = sadev;
+ dev->driver_data = ps2if;
+
+ spin_lock_init(&ps2if->lock);
+
/*
* Request the physical region for this PS2 port.
*/
- sa->res = request_mem_region(_SA1111(sa->base), 512, "ps2");
- if (!sa->res)
- return -EBUSY;
+ if (!request_mem_region(sadev->res.start,
+ sadev->res.end - sadev->res.start + 1,
+ SA1111_DRIVER_NAME(sadev))) {
+ ret = -EBUSY;
+ goto free;
+ }
/*
- * Convert the chip offset to virtual address.
+ * Our parent device has already mapped the region.
*/
- sa->base += (unsigned long)dev->base;
+ ps2if->base = (unsigned long)sadev->mapbase;
- sa1111_enable_device(sa->skpcr_mask);
+ sa1111_enable_device(ps2if->dev);
/* Incoming clock is 8MHz */
- sa1111_writel(0, sa->base + SA1111_PS2CLKDIV);
- sa1111_writel(127, sa->base + SA1111_PS2PRECNT);
+ sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV);
+ sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT);
/*
* Flush any pending input.
*/
- ps2_clear_input(sa);
+ ps2_clear_input(ps2if);
/*
* Test the keyboard interface.
*/
- ret = ps2_test(sa);
+ ret = ps2_test(ps2if);
if (ret)
goto out;
/*
* Flush any pending input.
*/
- ps2_clear_input(sa);
- sa1111_disable_device(sa->skpcr_mask);
+ ps2_clear_input(ps2if);
- serio_register_port(&sa->io);
+ sa1111_disable_device(ps2if->dev);
+ serio_register_port(&ps2if->io);
return 0;
out:
- sa1111_disable_device(sa->skpcr_mask);
- release_resource(sa->res);
+ sa1111_disable_device(ps2if->dev);
+ release_mem_region(sadev->res.start,
+ sadev->res.end - sadev->res.start + 1);
+ free:
+ dev->driver_data = NULL;
+ kfree(ps2if);
return ret;
}
/*
- * Remove one PS/2 port.
+ * Remove one device from this driver.
*/
-static void __exit ps2_remove_one(struct ps2if *sa)
+static int ps2_remove(struct device *dev)
{
- serio_unregister_port(&sa->io);
- release_resource(sa->res);
+ struct ps2if *ps2if = dev->driver_data;
+ struct sa1111_dev *sadev = SA1111_DEV(dev);
+
+ serio_unregister_port(&ps2if->io);
+ release_mem_region(sadev->res.start,
+ sadev->res.end - sadev->res.start + 1);
+ kfree(ps2if);
+
+ dev->driver_data = NULL;
+
+ return 0;
}
-static struct ps2if ps2_kbd_port =
+/*
+ * We should probably do something here, but what?
+ */
+static int ps2_suspend(struct device *dev, u32 state, u32 level)
{
- io: {
- type: SERIO_8042,
- write: ps2_write,
- open: ps2_open,
- close: ps2_close,
- name: "SA1111 PS/2 kbd port",
- phys: "sa1111/serio0",
- driver: &ps2_kbd_port,
- },
- base: SA1111_KBD,
- irq: IRQ_TPRXINT,
- skpcr_mask: SKPCR_PTCLKEN,
-};
+ return 0;
+}
-static struct ps2if ps2_mse_port =
+static int ps2_resume(struct device *dev, u32 level)
{
- io: {
- type: SERIO_8042,
- write: ps2_write,
- open: ps2_open,
- close: ps2_close,
- name: "SA1111 PS/2 mouse port",
- phys: "sa1111/serio1",
- driver: &ps2_mse_port,
+ return 0;
+}
+
+/*
+ * Our device driver structure
+ */
+static struct sa1111_driver ps2_driver = {
+ .drv = {
+ .name = "SA1111 PS2",
+ .bus = &sa1111_bus_type,
+ .probe = ps2_probe,
+ .remove = ps2_remove,
+ .suspend = ps2_suspend,
+ .resume = ps2_resume,
},
- base: SA1111_MSE,
- irq: IRQ_MSRXINT,
- skpcr_mask: SKPCR_PMCLKEN,
+ .devid = SA1111_DEVID_PS2,
};
static int __init ps2_init(void)
{
- int ret = -ENODEV;
-
- if (sa1111) {
- ret = ps2_init_one(sa1111, &ps2_kbd_port);
- }
-
- return ret;
+ return driver_register(&ps2_driver.drv);
}
static void __exit ps2_exit(void)
{
- ps2_remove_one(&ps2_kbd_port);
+ remove_driver(&ps2_driver.drv);
}
module_init(ps2_init);
fi
if [ "$CONFIG_ARM" = "y" ]; then
dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+ dep_tristate ' SA1111 support' CONFIG_PCMCIA_SA1111 $CONFIG_PCMCIA_SA1100 $CONFIG_SA1111 $CONFIG_PCMCIA
fi
fi
obj-$(CONFIG_TCIC) += tcic.o
obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o
obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o
+obj-$(CONFIG_PCMCIA_SA1111) += sa1111_cs.o
yenta_socket-objs := pci_socket.o yenta.o
pcmcia_core-objs-$(CONFIG_CARDBUS) += cardbus.o
pcmcia_core-objs := $(pcmcia_core-objs-y)
+sa1111_cs-objs-y := sa1111_generic.o
+sa1111_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o
+sa1111_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o
+sa1111_cs-objs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o
+sa1111_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o
+sa1111_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o
+sa1111_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o
+sa1111_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3) += sa1100_system3.o
+sa1111_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o
+sa1111_cs-objs := $(sa1111_cs-objs-y)
+
sa1100_cs-objs-y := sa1100_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o
-sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o
sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o
sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o
-sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o
sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o
-sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN) += sa1100_pangolin.o
-sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o sa1111_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3) += sa1100_system3.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o
sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o
sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o
sa1100_cs-objs-$(CONFIG_SA1100_TRIZEPS) += sa1100_trizeps.o
-sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o
sa1100_cs-objs := $(sa1100_cs-objs-y)
#include <linux/init.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include "sa1100_generic.h"
#include "sa1111_generic.h"
#include <linux/init.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include <asm/arch/badge4.h>
#include <asm/hardware/sa1111.h>
}
#endif
-#ifdef CONFIG_SA1100_ADSBITSY
- pcmcia_adsbitsy_init();
-#endif
#ifdef CONFIG_SA1100_ASSABET
pcmcia_assabet_init();
#endif
-#ifdef CONFIG_SA1100_BADGE4
- pcmcia_badge4_init();
-#endif
#ifdef CONFIG_SA1100_CERF
pcmcia_cerf_init();
#endif
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
pcmcia_gcplus_init();
#endif
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
- pcmcia_graphicsmaster_init();
-#endif
-#ifdef CONFIG_SA1100_JORNADA720
- pcmcia_jornada720_init();
-#endif
-#ifdef CONFIG_ASSABET_NEPONSET
- pcmcia_neponset_init();
-#endif
#ifdef CONFIG_SA1100_PANGOLIN
pcmcia_pangolin_init();
#endif
-#ifdef CONFIG_SA1100_PFS168
- pcmcia_pfs_init();
-#endif
-#ifdef CONFIG_SA1100_PT_SYSTEM3
- pcmcia_system3_init();
-#endif
#ifdef CONFIG_SA1100_SHANNON
pcmcia_shannon_init();
#endif
#ifdef CONFIG_SA1100_TRIZEPS
pcmcia_trizeps_init();
#endif
-#ifdef CONFIG_SA1100_XP860
- pcmcia_xp860_init();
-#endif
#ifdef CONFIG_SA1100_YOPY
pcmcia_yopy_init();
#endif
*/
static void __exit sa1100_pcmcia_exit(void)
{
-#ifdef CONFIG_SA1100_ADSBITSY
- pcmcia_adsbitsy_exit();
-#endif
#ifdef CONFIG_SA1100_ASSABET
pcmcia_assabet_exit();
#endif
-#ifdef CONFIG_SA1100_BADGE4
- pcmcia_badge4_exit();
-#endif
#ifdef CONFIG_SA1100_CERF
pcmcia_cerf_exit();
#endif
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
pcmcia_gcplus_exit();
#endif
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
- pcmcia_graphicsmaster_exit();
-#endif
-#ifdef CONFIG_SA1100_JORNADA720
- pcmcia_jornada720_exit();
-#endif
-#ifdef CONFIG_ASSABET_NEPONSET
- pcmcia_neponset_exit();
-#endif
#ifdef CONFIG_SA1100_PANGOLIN
pcmcia_pangolin_exit();
#endif
-#ifdef CONFIG_SA1100_PFS168
- pcmcia_pfs_exit();
-#endif
#ifdef CONFIG_SA1100_SHANNON
pcmcia_shannon_exit();
#endif
#ifdef CONFIG_SA1100_STORK
pcmcia_stork_exit();
#endif
-#ifdef CONFIG_SA1100_XP860
- pcmcia_xp860_exit();
-#endif
#ifdef CONFIG_SA1100_YOPY
pcmcia_yopy_exit();
#endif
#include <linux/init.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include "sa1100_generic.h"
#include "sa1111_generic.h"
#include <linux/init.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include "sa1100_generic.h"
#include "sa1111_generic.h"
#include <linux/init.h>
#include <asm/hardware.h>
-#include <asm/arch/assabet.h>
+#include <asm/mach-types.h>
+#include <asm/arch/neponset.h>
#include <asm/hardware/sa1111.h>
#include "sa1100_generic.h"
#include "sa1111_generic.h"
+/*
+ * Neponset uses the Maxim MAX1600, with the following connections:
+ *
+ * MAX1600 Neponset
+ *
+ * A0VCC SA-1111 GPIO A<1>
+ * A1VCC SA-1111 GPIO A<0>
+ * A0VPP CPLD NCR A0VPP
+ * A1VPP CPLD NCR A1VPP
+ * B0VCC SA-1111 GPIO A<2>
+ * B1VCC SA-1111 GPIO A<3>
+ * B0VPP ground (slot B is CF)
+ * B1VPP ground (slot B is CF)
+ *
+ * VX VCC (5V)
+ * VY VCC3_3 (3.3V)
+ * 12INA 12V
+ * 12INB ground (slot B is CF)
+ *
+ * The MAX1600 CODE pin is tied to ground, placing the device in
+ * "Standard Intel code" mode. Refer to the Maxim data sheet for
+ * the corresponding truth table.
+ */
+
static int neponset_pcmcia_init(struct pcmcia_init *init)
{
- /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
- PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
-
- /* MAX1600 to standby mode: */
- PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
+ /*
+ * Set GPIO_A<3:0> to be outputs for the MAX1600,
+ * and switch to standby mode.
+ */
+ PA_DDR = 0;
+ PA_SDR = 0;
+ PA_DWR = 0;
+ PA_SSR = 0;
+
return sa1111_pcmcia_init(init);
}
unsigned int ncr_set, pa_dwr_set;
int ret;
- /* Neponset uses the Maxim MAX1600, with the following connections:
-
- * MAX1600 Neponset
- *
- * A0VCC SA-1111 GPIO A<1>
- * A1VCC SA-1111 GPIO A<0>
- * A0VPP CPLD NCR A0VPP
- * A1VPP CPLD NCR A1VPP
- * B0VCC SA-1111 GPIO A<2>
- * B1VCC SA-1111 GPIO A<3>
- * B0VPP ground (slot B is CF)
- * B1VPP ground (slot B is CF)
- *
- * VX VCC (5V)
- * VY VCC3_3 (3.3V)
- * 12INA 12V
- * 12INB ground (slot B is CF)
- *
- * The MAX1600 CODE pin is tied to ground, placing the device in
- * "Standard Intel code" mode. Refer to the Maxim data sheet for
- * the corresponding truth table.
- */
-
switch (conf->sock) {
case 0:
pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
{
int ret = -ENODEV;
- if (machine_is_assabet() && sa1111)
+ if (machine_is_assabet())
ret = sa1100_register_pcmcia(&neponset_pcmcia_ops);
return ret;
}
-void __exit pcmcia_neponset_exit(void)
+void __devexit pcmcia_neponset_exit(void)
{
sa1100_unregister_pcmcia(&neponset_pcmcia_ops);
}
*/
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/delay.h>
#include <linux/init.h>
-#include <asm/delay.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include <asm/irq.h>
#include "sa1100_generic.h"
#include <linux/ioport.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include <asm/irq.h>
#include <asm/hardware/sa1111.h>
#include <linux/init.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include <asm/irq.h>
#include "sa1100_generic.h"
* basically means we handle everything except controlling the
* power. Power is machine specific...
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/device.h>
+#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/hardware/sa1111.h>
int irq;
const char *str;
} irqs[] = {
- { S0_CD_VALID, "SA1111 PCMCIA card detect" },
- { S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" },
- { S1_CD_VALID, "SA1111 CF card detect" },
- { S1_BVD1_STSCHG, "SA1111 CF BVD1" },
+ { IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" },
+ { IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" },
+ { IRQ_S1_CD_VALID, "SA1111 CF card detect" },
+ { IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" },
};
+static struct sa1111_dev *pcmcia;
+
int sa1111_pcmcia_init(struct pcmcia_init *init)
{
int i, ret;
- if (!request_mem_region(_PCCR, 512, "PCMCIA"))
- return -1;
-
for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) {
set_irq_type(irqs[i].irq, IRQT_FALLING);
ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irqs[i].irq, ret);
while (i--)
free_irq(irqs[i].irq, NULL);
-
- release_mem_region(_PCCR, 16);
}
return ret ? -1 : 2;
for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
- release_mem_region(_PCCR, 512);
-
return 0;
}
if (state->size < 2)
return -1;
- status = PCSR;
+ status = sa1111_readl(pcmcia->mapbase + SA1111_PCSR);
state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1;
state->state[0].ready = status & PCSR_S0_READY ? 1 : 0;
int ret = 0;
switch (info->sock) {
- case 0: info->irq = S0_READY_NINT; break;
- case 1: info->irq = S1_READY_NINT; break;
+ case 0: info->irq = IRQ_S0_READY_NINT; break;
+ case 1: info->irq = IRQ_S1_READY_NINT; break;
default: ret = 1;
}
int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{
- unsigned int rst, flt, wait, pse, irq, pccr_mask;
+ unsigned int rst, flt, wait, pse, irq, pccr_mask, val;
unsigned long flags;
switch (conf->sock) {
flt = PCCR_S0_FLT;
wait = PCCR_S0_PWAITEN;
pse = PCCR_S0_PSE;
- irq = S0_READY_NINT;
+ irq = IRQ_S0_READY_NINT;
break;
case 1:
flt = PCCR_S1_FLT;
wait = PCCR_S1_PWAITEN;
pse = PCCR_S1_PSE;
- irq = S1_READY_NINT;
+ irq = IRQ_S1_READY_NINT;
break;
default:
pccr_mask |= flt;
local_irq_save(flags);
- PCCR = (PCCR & ~(pse | flt | wait | rst)) | pccr_mask;
+ val = sa1111_readl(pcmcia->mapbase + SA1111_PCCR);
+ val = (val & ~(pse | flt | wait | rst)) | pccr_mask;
+ sa1111_writel(val, pcmcia->mapbase + SA1111_PCCR);
local_irq_restore(flags);
if (conf->irq)
{
return 0;
}
+
+static int pcmcia_probe(struct device *dev)
+{
+ struct sa1111_dev *sadev = SA1111_DEV(dev);
+ unsigned long flags;
+ char *base;
+
+ local_irq_save(flags);
+ if (pcmcia) {
+ local_irq_restore(flags);
+ return -EBUSY;
+ }
+
+ pcmcia = sadev;
+ local_irq_restore(flags);
+
+ if (!request_mem_region(sadev->res.start, 512,
+ SA1111_DRIVER_NAME(sadev)))
+ return -EBUSY;
+
+ base = sadev->mapbase;
+
+ /*
+ * 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);
+
+#ifdef CONFIG_SA1100_ADSBITSY
+ pcmcia_adsbitsy_init();
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+ pcmcia_badge4_init();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+ pcmcia_graphicsmaster_init();
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+ pcmcia_jornada720_init();
+#endif
+#ifdef CONFIG_ASSABET_NEPONSET
+ pcmcia_neponset_init();
+#endif
+#ifdef CONFIG_SA1100_PFS168
+ pcmcia_pfs_init();
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+ pcmcia_system3_init();
+#endif
+#ifdef CONFIG_SA1100_XP860
+ pcmcia_xp860_init();
+#endif
+ return 0;
+}
+
+static int __devexit pcmcia_remove(struct device *dev)
+{
+ struct sa1111_dev *sadev = SA1111_DEV(dev);
+
+#ifdef CONFIG_SA1100_ADSBITSY
+ pcmcia_adsbitsy_exit();
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+ pcmcia_badge4_exit();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+ pcmcia_graphicsmaster_exit();
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+ pcmcia_jornada720_exit();
+#endif
+#ifdef CONFIG_ASSABET_NEPONSET
+ pcmcia_neponset_exit();
+#endif
+#ifdef CONFIG_SA1100_PFS168
+ pcmcia_pfs_exit();
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+ pcmcia_system3_exit();
+#endif
+#ifdef CONFIG_SA1100_XP860
+ pcmcia_xp860_exit();
+#endif
+
+ release_mem_region(sadev->res.start, 512);
+ pcmcia = NULL;
+
+ return 0;
+}
+
+static int pcmcia_suspend(struct device *dev, u32 state, u32 level)
+{
+ return 0;
+}
+
+static int pcmcia_resume(struct device *dev, u32 level)
+{
+ return 0;
+}
+
+static struct sa1111_driver pcmcia_driver = {
+ .drv = {
+ .name = "SA1111 PCMCIA",
+ .bus = &sa1111_bus_type,
+ .probe = pcmcia_probe,
+ .remove = __devexit_p(pcmcia_remove),
+ .suspend = pcmcia_suspend,
+ .resume = pcmcia_resume,
+ },
+ .devid = SA1111_DEVID_PCMCIA,
+};
+
+static int __init sa1111_drv_pcmcia_init(void)
+{
+ return driver_register(&pcmcia_driver.drv);
+}
+
+static void __exit sa1111_drv_pcmcia_exit(void)
+{
+ remove_driver(&pcmcia_driver.drv);
+}
+
+module_init(sa1111_drv_pcmcia_init);
+module_exit(sa1111_drv_pcmcia_exit);
+
+MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
+MODULE_LICENSE("GPL");
/*-------------------------------------------------------------------------*/
-static void sa1111_start_hc(void)
+static void sa1111_start_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst = 0;
* Configure the power sense and control lines. Place the USB
* host controller in reset.
*/
- USB_RESET = usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
+ sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+ dev->mapbase + SA1111_USB_RESET);
/*
* Now, carefully enable the USB clock, and take
* the USB host controller out of reset.
*/
- SKPCR |= SKPCR_UCLKEN;
+ sa1111_enable_device(dev);
udelay(11);
- USB_RESET = usb_rst;
+ sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
}
-static void sa1111_stop_hc(void)
+static void sa1111_stop_hc(struct sa1111_dev *dev)
{
+ unsigned int usb_rst;
printk(KERN_DEBUG __FILE__
": stopping SA-1111 OHCI USB Controller\n");
/*
* Put the USB host controller into reset.
*/
- USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
+ usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
+ sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+ dev->mapbase + SA1111_USB_RESET);
/*
* Stop the USB clock.
*/
- SKPCR &= ~SKPCR_UCLKEN;
+ sa1111_disable_device(dev);
#ifdef CONFIG_SA1100_BADGE4
if (machine_is_badge4()) {
/*-------------------------------------------------------------------------*/
#if 0
-static void dump_hci_status(const char *label)
+static void dump_hci_status(struct usb_hcd *hcd, const char *label)
{
- unsigned long status = USB_STATUS;
+ 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 " : ""),
static void usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
{
- //dump_hci_status("irq");
+ struct usb_hcd *hcd = __hcd;
+// unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
+
+ //dump_hci_status(hcd, "irq");
#if 0
/* may work better this way -- need to investigate further */
- if (USB_STATUS & USB_STATUS_NIRQHCIM) {
+ if (status & USB_STATUS_NIRQHCIM) {
//dbg ("not normal HC interrupt; ignoring");
return;
}
/*-------------------------------------------------------------------------*/
-void usb_hcd_sa1111_remove (struct usb_hcd *);
+void usb_hcd_sa1111_remove (struct usb_hcd *, struct sa1111_dev *);
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
*
* Store this function in the HCD's struct pci_driver as probe().
*/
-int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_out)
+int usb_hcd_sa1111_probe (const struct hc_driver *driver,
+ struct usb_hcd **hcd_out,
+ struct sa1111_dev *dev)
{
int retval;
struct usb_hcd *hcd = 0;
- if (!sa1111)
- return -ENODEV;
-
- if (!request_mem_region(_USB_OHCI_OP_BASE,
- _USB_EXTENT, hcd_name)) {
+ if (!request_mem_region(dev->res.start,
+ dev->res.end - dev->res.start + 1, hcd_name)) {
dbg("request_mem_region failed");
return -EBUSY;
}
- sa1111_start_hc();
+ sa1111_start_hc(dev);
hcd = driver->hcd_alloc ();
if (hcd == NULL){
hcd->driver = (struct hc_driver *) driver;
hcd->description = driver->description;
- hcd->irq = NIRQHCIM;
- hcd->regs = (void *) &USB_OHCI_OP_BASE;
+ hcd->irq = dev->irq[1];
+ hcd->regs = dev->mapbase;
hcd->pdev = SA1111_FAKE_PCIDEV;
+ hcd->parent = &dev->dev;
retval = hcd_buffer_create (hcd);
if (retval != 0) {
goto err1;
}
- set_irq_type(NIRQHCIM, IRQT_RISING);
- retval = request_irq (NIRQHCIM, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
+ set_irq_type(hcd->irq, IRQT_RISING);
+ retval = request_irq (hcd->irq, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
hcd->description, hcd);
if (retval != 0) {
dbg("request_irq failed");
if ((retval = driver->start (hcd)) < 0)
{
- usb_hcd_sa1111_remove(hcd);
+ usb_hcd_sa1111_remove(hcd, dev);
return retval;
}
hcd_buffer_destroy (hcd);
if (hcd) driver->hcd_free(hcd);
err1:
- sa1111_stop_hc();
- release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+ sa1111_stop_hc(dev);
+ release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
return retval;
}
* context, normally "rmmod", "apmd", or something similar.
*
*/
-void usb_hcd_sa1111_remove (struct usb_hcd *hcd)
+void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
{
struct usb_device *hub;
void *base;
usb_deregister_bus (&hcd->self);
if (atomic_read (&hcd->self.refcnt) != 1)
- err (__FUNCTION__ ": %s, count != 1", hcd->self.bus_name);
+ err ("%s: %s, count != 1", __FUNCTION__, hcd->self.bus_name);
base = hcd->regs;
hcd->driver->hcd_free (hcd);
- sa1111_stop_hc();
- release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+ sa1111_stop_hc(dev);
+ release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
}
/*-------------------------------------------------------------------------*/
}
ohci->regs = hcd->regs;
- ohci->parent_dev = &sa1111->dev;
+ ohci->parent_dev = hcd->parent;
if (hc_reset (ohci) < 0) {
ohci_stop (hcd);
/*-------------------------------------------------------------------------*/
-/* Only one SA-1111 ever exists. */
-static struct usb_hcd *the_sa1111_hcd;
+static int ohci_hcd_sa1111_drv_probe(struct device *_dev)
+{
+ struct sa1111_dev *dev = SA1111_DEV(_dev);
+ struct usb_hcd *hcd = NULL;
+ int ret;
+
+ ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev);
+
+ if (ret == 0)
+ dev->dev.driver_data = hcd;
+
+ return ret;
+}
+
+static int ohci_hcd_sa1111_drv_remove(struct device *_dev)
+{
+ struct sa1111_dev *dev = SA1111_DEV(_dev);
+ struct usb_hcd *hcd = dev->dev.driver_data;
+
+ usb_hcd_sa1111_remove(hcd, dev);
+
+ dev->dev.driver_data = NULL;
-static int __init ohci_hcd_sa1111_init (void)
+ return 0;
+}
+
+static int ohci_hcd_sa1111_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+ return 0;
+}
+
+static int ohci_hcd_sa1111_drv_resume(struct device *dev, u32 level)
+{
+ return 0;
+}
+
+static struct sa1111_driver ohci_hcd_sa1111_driver = {
+ .drv = {
+ .name = "SA1111 OHCI",
+ .bus = &sa1111_bus_type,
+ .probe = ohci_hcd_sa1111_drv_probe,
+ .remove = ohci_hcd_sa1111_drv_remove,
+ .suspend = ohci_hcd_sa1111_drv_suspend,
+ .resume = ohci_hcd_sa1111_drv_resume,
+ },
+ .devid = SA1111_DEVID_USB,
+};
+
+static int __init ohci_hcd_sa1111_init (void)
{
dbg (DRIVER_INFO " (SA-1111)");
dbg ("block sizes: ed %d td %d",
sizeof (struct ed), sizeof (struct td));
- the_sa1111_hcd = 0;
- return usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &the_sa1111_hcd);
+ return driver_register(&ohci_hcd_sa1111_driver.drv);
}
-module_init (ohci_hcd_sa1111_init);
-
-static void __exit ohci_hcd_sa1111_cleanup (void)
-{
- if (the_sa1111_hcd) {
- usb_hcd_sa1111_remove(the_sa1111_hcd);
- the_sa1111_hcd = 0;
- }
+static void __exit ohci_hcd_sa1111_cleanup (void)
+{
+ remove_driver(&ohci_hcd_sa1111_driver.drv);
}
+
+module_init (ohci_hcd_sa1111_init);
module_exit (ohci_hcd_sa1111_cleanup);
#define SA1111_SMCR 0x0004
#define SA1111_SKID 0x0008
-#define _SBI_SKCR _SA1111(SA1111_SKCR)
-#define _SBI_SMCR _SA1111(SA1111_SMCR)
-#define _SBI_SKID _SA1111(SA1111_SKID)
-
-#if LANGUAGE == C
-
#define SBI_SKCR __CCREG(SA1111_SKCR)
#define SBI_SMCR __CCREG(SA1111_SMCR)
#define SBI_SKID __CCREG(SA1111_SKID)
-#endif /* LANGUAGE == C */
-
#define SKCR_PLL_BYPASS (1<<0)
#define SKCR_RCLKEN (1<<1)
#define SKCR_SLEEP (1<<2)
#define SA1111_SKPMC 0x020c
#define SA1111_SKPTC 0x0210
#define SA1111_SKPEN0 0x0214
-#define SA1111_SKPWN0 0x0218
+#define SA1111_SKPWM0 0x0218
#define SA1111_SKPEN1 0x021c
#define SA1111_SKPWM1 0x0220
-#define _SKPCR _SA1111(SA1111_SKPCR)
-#define _SKCDR _SA1111(SA1111_SKCDR)
-#define _SKAUD _SA1111(SA1111_SKAUD)
-#define _SKPMC _SA1111(SA1111_SKPMC)
-#define _SKPTC _SA1111(SA1111_SKPTC)
-#define _SKPEN0 _SA1111(SA1111_SKPEN0)
-#define _SKPWM0 _SA1111(SA1111_SKPWM0)
-#define _SKPEN1 _SA1111(SA1111_SKPEN1)
-#define _SKPWM1 _SA1111(SA1111_SKPWM1)
-
-#if LANGUAGE == C
-
#define SKPCR __CCREG(SA1111_SKPCR)
#define SKCDR __CCREG(SA1111_SKCDR)
#define SKAUD __CCREG(SA1111_SKAUD)
#define SKPEN1 __CCREG(SA1111_SKPEN1)
#define SKPWM1 __CCREG(SA1111_SKPWM1)
-#endif /* LANGUAGE == C */
-
#define SKPCR_UCLKEN (1<<0)
#define SKPCR_ACCLKEN (1<<1)
#define SKPCR_I2SCLKEN (1<<2)
/*
* USB Host controller
*/
-#define _USB_OHCI_OP_BASE _SA1111( 0x400 )
-#define _USB_STATUS _SA1111( 0x518 )
-#define _USB_RESET _SA1111( 0x51c )
-#define _USB_INTERRUPTEST _SA1111( 0x520 )
-
-#define _USB_EXTENT (_USB_INTERRUPTEST - _USB_OHCI_OP_BASE + 4)
+#define SA1111_USB 0x0400
-#if LANGUAGE == C
-
-#define USB_OHCI_OP_BASE __CCREG(0x0400)
-#define USB_STATUS __CCREG(0x0518)
-#define USB_RESET __CCREG(0x051c)
-#define USB_INTERRUPTEST __CCReG(0x0520)
-
-#endif /* LANGUAGE == C */
+/*
+ * 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)
* WAKE_POL0 Wake-up polarity selection 0
* WAKE_POL1 Wake-up polarity selection 1
*/
+#define SA1111_INTC 0x1600
-#define SA1111_INTTEST0 0x1600
-#define SA1111_INTTEST1 0x1604
-#define SA1111_INTEN0 0x1608
-#define SA1111_INTEN1 0x160c
-#define SA1111_INTPOL0 0x1610
-#define SA1111_INTPOL1 0x1614
-#define SA1111_INTTSTSEL 0x1618
-#define SA1111_INTSTATCLR0 0x161c
-#define SA1111_INTSTATCLR1 0x1620
-#define SA1111_INTSET0 0x1624
-#define SA1111_INTSET1 0x1628
-#define SA1111_WAKE_EN0 0x162c
-#define SA1111_WAKE_EN1 0x1630
-#define SA1111_WAKE_POL0 0x1634
-#define SA1111_WAKE_POL1 0x1638
-
-#define _INTTEST0 _SA1111(SA1111_INTTEST0)
-#define _INTTEST1 _SA1111(SA1111_INTTEST1)
-#define _INTEN0 _SA1111(SA1111_INTEN0)
-#define _INTEN1 _SA1111(SA1111_INTEN1)
-#define _INTPOL0 _SA1111(SA1111_INTPOL0)
-#define _INTPOL1 _SA1111(SA1111_INTPOL1)
-#define _INTTSTSEL _SA1111(SA1111_INTTSTSEL)
-#define _INTSTATCLR0 _SA1111(SA1111_INTSTATCLR0)
-#define _INTSTATCLR1 _SA1111(SA1111_INTSTATCLR1)
-#define _INTSET0 _SA1111(SA1111_INTSET0)
-#define _INTSET1 _SA1111(SA1111_INTSET1)
-#define _WAKE_EN0 _SA1111(SA1111_WAKE_EN0)
-#define _WAKE_EN1 _SA1111(SA1111_WAKE_EN1)
-#define _WAKE_POL0 _SA1111(SA1111_WAKE_POL0)
-#define _WAKE_POL1 _SA1111(SA1111_WAKE_POL1)
-
-#if LANGUAGE == C
-
-#define INTTEST0 __CCREG(SA1111_INTTEST0)
-#define INTTEST1 __CCREG(SA1111_INTTEST1)
-#define INTEN0 __CCREG(SA1111_INTEN0)
-#define INTEN1 __CCREG(SA1111_INTEN1)
-#define INTPOL0 __CCREG(SA1111_INTPOL0)
-#define INTPOL1 __CCREG(SA1111_INTPOL1)
-#define INTTSTSEL __CCREG(SA1111_INTTSTSEL)
-#define INTSTATCLR0 __CCREG(SA1111_INTSTATCLR0)
-#define INTSTATCLR1 __CCREG(SA1111_INTSTATCLR1)
-#define INTSET0 __CCREG(SA1111_INTSET0)
-#define INTSET1 __CCREG(SA1111_INTSET1)
-#define WAKE_EN0 __CCREG(SA1111_WAKE_EN0)
-#define WAKE_EN1 __CCREG(SA1111_WAKE_EN1)
-#define WAKE_POL0 __CCREG(SA1111_WAKE_POL0)
-#define WAKE_POL1 __CCREG(SA1111_WAKE_POL1)
-
-#endif /* LANGUAGE == C */
+/*
+ * These are offsets from the above base.
+ */
+#define SA1111_INTTEST0 0x0000
+#define SA1111_INTTEST1 0x0004
+#define SA1111_INTEN0 0x0008
+#define SA1111_INTEN1 0x000c
+#define SA1111_INTPOL0 0x0010
+#define SA1111_INTPOL1 0x0014
+#define SA1111_INTTSTSEL 0x0018
+#define SA1111_INTSTATCLR0 0x001c
+#define SA1111_INTSTATCLR1 0x0020
+#define SA1111_INTSET0 0x0024
+#define SA1111_INTSET1 0x0028
+#define SA1111_WAKEEN0 0x002c
+#define SA1111_WAKEEN1 0x0030
+#define SA1111_WAKEPOL0 0x0034
+#define SA1111_WAKEPOL1 0x0038
+
+#define INTTEST0 __CCREG(SA1111_INTC + SA1111_INTTEST0)
+#define INTTEST1 __CCREG(SA1111_INTC + SA1111_INTTEST1)
+#define INTEN0 __CCREG(SA1111_INTC + SA1111_INTEN0)
+#define INTEN1 __CCREG(SA1111_INTC + SA1111_INTEN1)
+#define INTPOL0 __CCREG(SA1111_INTC + SA1111_INTPOL0)
+#define INTPOL1 __CCREG(SA1111_INTC + SA1111_INTPOL1)
+#define INTTSTSEL __CCREG(SA1111_INTC + SA1111_INTTSTSEL)
+#define INTSTATCLR0 __CCREG(SA1111_INTC + SA1111_INTSTATCLR0)
+#define INTSTATCLR1 __CCREG(SA1111_INTC + SA1111_INTSTATCLR1)
+#define INTSET0 __CCREG(SA1111_INTC + SA1111_INTSET0)
+#define INTSET1 __CCREG(SA1111_INTC + SA1111_INTSET1)
+#define WAKE_EN0 __CCREG(SA1111_INTC + SA1111_WAKEEN0)
+#define WAKE_EN1 __CCREG(SA1111_INTC + SA1111_WAKEEN1)
+#define WAKE_POL0 __CCREG(SA1111_INTC + SA1111_WAKEPOL0)
+#define WAKE_POL1 __CCREG(SA1111_INTC + SA1111_WAKEPOL1)
/*
* PS/2 Trackpad and Mouse Interfaces
*
- * Registers (prefix kbd applies to trackpad interface, mse to mouse)
- * KBDCR Control Register
- * KBDSTAT Status Register
- * KBDDATA Transmit/Receive Data register
- * KBDCLKDIV Clock Division Register
- * KBDPRECNT Clock Precount Register
- * KBDTEST1 Test register 1
- * KBDTEST2 Test register 2
- * KBDTEST3 Test register 3
- * KBDTEST4 Test register 4
- * MSECR
- * MSESTAT
- * MSEDATA
- * MSECLKDIV
- * MSEPRECNT
- * MSETEST1
- * MSETEST2
- * MSETEST3
- * MSETEST4
- *
+ * 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
*/
#define SA1111_KBD 0x0a00
* PCSSR Sleep State Register
*/
-#define _PCCR _SA1111( 0x1800 )
-#define _PCSSR _SA1111( 0x1804 )
-#define _PCSR _SA1111( 0x1808 )
-
-#if LANGUAGE == C
-
-#define PCCR __CCREG(0x1800)
-#define PCSSR __CCREG(0x1804)
-#define PCSR __CCREG(0x1808)
+#define SA1111_PCMCIA 0x1600
-#endif /* LANGUAGE == C */
+/*
+ * 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 PCSSR_S0_SLEEP (1<<0)
#define PCSSR_S1_SLEEP (1<<1)
-struct sa1111_device {
+
+
+
+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
+
+struct sa1111_dev {
struct device dev;
- struct resource resource;
- void *base;
+ unsigned int devid;
+ struct resource res;
+ void *mapbase;
+ unsigned int skpcr_mask;
+ unsigned int irq[6];
};
-extern struct sa1111_device *sa1111;
+#define SA1111_DEV(_d) container_of((_d), struct sa1111_dev, dev)
-int sa1111_check_dma_bug(dma_addr_t addr);
+struct sa1111_driver {
+ struct device_driver drv;
+ unsigned int devid;
+};
+
+#define SA1111_DRV(_d) container_of((_d), struct sa1111_driver, drv)
+
+#define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name)
/*
* These frob the SKPCR register.
*/
-void sa1111_enable_device(unsigned int mask);
-void sa1111_disable_device(unsigned int mask);
+void sa1111_enable_device(struct sa1111_dev *);
+void sa1111_disable_device(struct sa1111_dev *);
+
+unsigned int sa1111_pll_clock(struct sa1111_dev *);
+
+#define SA1111_AUDIO_ACLINK 0
+#define SA1111_AUDIO_I2S 1
+void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode);
+int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate);
+int sa1111_get_audio_rate(struct sa1111_dev *sadev);
+
+int sa1111_check_dma_bug(dma_addr_t addr);
#endif /* _ASM_ARCH_SA1111 */