summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2007-10-15 18:55:44 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-10-15 18:56:02 +0100
commit0181b61a988424b5cc44fe09e6968142359c815e (patch)
tree2575ee900a39ffaa169ad5aeb8aa6ddee11cfbe5 /drivers
parent92633b72d18ca4f25de1f28e436a882159491e7e (diff)
parent87944f3361fc033b73617aa663135c6e468957a7 (diff)
Merge branch 'pxa' into devel
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-pxa.c45
-rw-r--r--drivers/input/keyboard/pxa27x_keyboard.c25
-rw-r--r--drivers/leds/Kconfig6
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-cm-x270.c122
-rw-r--r--drivers/mmc/host/pxamci.c43
-rw-r--r--drivers/mmc/host/pxamci.h14
-rw-r--r--drivers/net/irda/pxaficp_ir.c51
-rw-r--r--drivers/net/smc91x.c55
-rw-r--r--drivers/net/smc91x.h64
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/pxa2xx_cm_x270.c175
-rw-r--r--drivers/pcmcia/pxa2xx_lubbock.c31
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c18
-rw-r--r--drivers/serial/pxa.c163
-rw-r--r--drivers/serial/serial_core.c18
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c68
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h1
-rw-r--r--drivers/video/pxafb.c36
-rw-r--r--drivers/video/pxafb.h1
20 files changed, 651 insertions, 287 deletions
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index bb5466b27b59..00fad11733ad 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -31,6 +31,8 @@
#include <linux/interrupt.h>
#include <linux/i2c-pxa.h>
#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
#include <asm/hardware.h>
#include <asm/irq.h>
@@ -48,6 +50,7 @@ struct pxa_i2c {
unsigned int slave_addr;
struct i2c_adapter adap;
+ struct clk *clk;
#ifdef CONFIG_I2C_PXA_SLAVE
struct i2c_slave_client *slave;
#endif
@@ -869,6 +872,12 @@ static int i2c_pxa_probe(struct platform_device *dev)
sprintf(i2c->adap.name, "pxa_i2c-i2c.%u", dev->id);
+ i2c->clk = clk_get(&dev->dev, "I2CCLK");
+ if (IS_ERR(i2c->clk)) {
+ ret = PTR_ERR(i2c->clk);
+ goto eclk;
+ }
+
i2c->reg_base = ioremap(res->start, res_len(res));
if (!i2c->reg_base) {
ret = -EIO;
@@ -889,22 +898,19 @@ static int i2c_pxa_probe(struct platform_device *dev)
}
#endif
+ clk_enable(i2c->clk);
+#ifdef CONFIG_PXA27x
switch (dev->id) {
case 0:
-#ifdef CONFIG_PXA27x
pxa_gpio_mode(GPIO117_I2CSCL_MD);
pxa_gpio_mode(GPIO118_I2CSDA_MD);
-#endif
- pxa_set_cken(CKEN_I2C, 1);
break;
-#ifdef CONFIG_PXA27x
case 1:
local_irq_disable();
PCFR |= PCFR_PI2CEN;
local_irq_enable();
- pxa_set_cken(CKEN_PWRI2C, 1);
-#endif
}
+#endif
ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
i2c->adap.name, i2c);
@@ -948,19 +954,18 @@ static int i2c_pxa_probe(struct platform_device *dev)
eadapt:
free_irq(irq, i2c);
ereqirq:
- switch (dev->id) {
- case 0:
- pxa_set_cken(CKEN_I2C, 0);
- break;
+ clk_disable(i2c->clk);
+
#ifdef CONFIG_PXA27x
- case 1:
- pxa_set_cken(CKEN_PWRI2C, 0);
+ if (dev->id == 1) {
local_irq_disable();
PCFR &= ~PCFR_PI2CEN;
local_irq_enable();
-#endif
}
+#endif
eremap:
+ clk_put(i2c->clk);
+eclk:
kfree(i2c);
emalloc:
release_mem_region(res->start, res_len(res));
@@ -975,18 +980,18 @@ static int i2c_pxa_remove(struct platform_device *dev)
i2c_del_adapter(&i2c->adap);
free_irq(i2c->irq, i2c);
- switch (dev->id) {
- case 0:
- pxa_set_cken(CKEN_I2C, 0);
- break;
+
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
#ifdef CONFIG_PXA27x
- case 1:
- pxa_set_cken(CKEN_PWRI2C, 0);
+ if (dev->id == 1) {
local_irq_disable();
PCFR &= ~PCFR_PI2CEN;
local_irq_enable();
-#endif
}
+#endif
+
release_mem_region(i2c->iobase, i2c->iosize);
kfree(i2c);
diff --git a/drivers/input/keyboard/pxa27x_keyboard.c b/drivers/input/keyboard/pxa27x_keyboard.c
index ebe5eacf2990..b7061aa38816 100644
--- a/drivers/input/keyboard/pxa27x_keyboard.c
+++ b/drivers/input/keyboard/pxa27x_keyboard.c
@@ -23,6 +23,8 @@
#include <linux/input.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -40,6 +42,8 @@
col/2 == 2 ? KPASMKP2 : KPASMKP3)
#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
+static struct clk *pxakbd_clk;
+
static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
@@ -104,7 +108,7 @@ static int pxakbd_open(struct input_dev *dev)
KPREC = 0x7F;
/* Enable unit clock */
- pxa_set_cken(CKEN_KEYPAD, 1);
+ clk_enable(pxakbd_clk);
return 0;
}
@@ -112,7 +116,7 @@ static int pxakbd_open(struct input_dev *dev)
static void pxakbd_close(struct input_dev *dev)
{
/* Disable clock unit */
- pxa_set_cken(CKEN_KEYPAD, 0);
+ clk_disable(pxakbd_clk);
}
#ifdef CONFIG_PM
@@ -140,7 +144,8 @@ static int pxakbd_resume(struct platform_device *pdev)
KPREC = pdata->reg_kprec;
/* Enable unit clock */
- pxa_set_cken(CKEN_KEYPAD, 1);
+ clk_disable(pxakbd_clk);
+ clk_enable(pxakbd_clk);
}
mutex_unlock(&input_dev->mutex);
@@ -158,11 +163,18 @@ static int __devinit pxakbd_probe(struct platform_device *pdev)
struct input_dev *input_dev;
int i, row, col, error;
+ pxakbd_clk = clk_get(&pdev->dev, "KBDCLK");
+ if (IS_ERR(pxakbd_clk)) {
+ error = PTR_ERR(pxakbd_clk);
+ goto err_clk;
+ }
+
/* Create and register the input driver. */
input_dev = input_allocate_device();
if (!input_dev) {
printk(KERN_ERR "Cannot request keypad device\n");
- return -ENOMEM;
+ error = -ENOMEM;
+ goto err_alloc;
}
input_dev->name = DRIVER_NAME;
@@ -185,7 +197,6 @@ static int __devinit pxakbd_probe(struct platform_device *pdev)
DRIVER_NAME, pdev);
if (error) {
printk(KERN_ERR "Cannot request keypad IRQ\n");
- pxa_set_cken(CKEN_KEYPAD, 0);
goto err_free_dev;
}
@@ -217,6 +228,9 @@ static int __devinit pxakbd_probe(struct platform_device *pdev)
free_irq(IRQ_KEYPAD, pdev);
err_free_dev:
input_free_device(input_dev);
+ err_alloc:
+ clk_put(pxakbd_clk);
+ err_clk:
return error;
}
@@ -226,6 +240,7 @@ static int __devexit pxakbd_remove(struct platform_device *pdev)
input_unregister_device(input_dev);
free_irq(IRQ_KEYPAD, pdev);
+ clk_put(pxakbd_clk);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 3cb23210b912..257b44094e4c 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -108,6 +108,12 @@ config LEDS_GPIO
outputs. To be useful the particular board must have LEDs
and they must be connected to the GPIO lines.
+config LEDS_CM_X270
+ tristate "LED Support for the CM-X270 LEDs"
+ depends on LEDS_CLASS && MACH_ARMCORE
+ help
+ This option enables support for the CM-X270 LEDs.
+
comment "LED Triggers"
config LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index d2ca1abbc3d2..a60de1b46c2c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
+obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/leds-cm-x270.c b/drivers/leds/leds-cm-x270.c
new file mode 100644
index 000000000000..9aebef02a974
--- /dev/null
+++ b/drivers/leds/leds-cm-x270.c
@@ -0,0 +1,122 @@
+/*
+ * drivers/leds/leds-cm-x270.c
+ *
+ * Copyright 2007 CompuLab Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on leds-corgi.c
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#define GPIO_RED_LED (93)
+#define GPIO_GREEN_LED (94)
+
+static void cmx270_red_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value)
+ GPCR(GPIO_RED_LED) = GPIO_bit(GPIO_RED_LED);
+ else
+ GPSR(GPIO_RED_LED) = GPIO_bit(GPIO_RED_LED);
+}
+
+static void cmx270_green_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value)
+ GPCR(GPIO_GREEN_LED) = GPIO_bit(GPIO_GREEN_LED);
+ else
+ GPSR(GPIO_GREEN_LED) = GPIO_bit(GPIO_GREEN_LED);
+}
+
+static struct led_classdev cmx270_red_led = {
+ .name = "cm-x270:red",
+ .default_trigger = "nand-disk",
+ .brightness_set = cmx270_red_set,
+};
+
+static struct led_classdev cmx270_green_led = {
+ .name = "cm-x270:green",
+ .default_trigger = "heartbeat",
+ .brightness_set = cmx270_green_set,
+};
+
+#ifdef CONFIG_PM
+static int cmx270led_suspend(struct platform_device *dev, pm_message_t state)
+{
+ led_classdev_suspend(&cmx270_red_led);
+ led_classdev_suspend(&cmx270_green_led);
+ return 0;
+}
+
+static int cmx270led_resume(struct platform_device *dev)
+{
+ led_classdev_resume(&cmx270_red_led);
+ led_classdev_resume(&cmx270_green_led);
+ return 0;
+}
+#endif
+
+static int cmx270led_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = led_classdev_register(&pdev->dev, &cmx270_red_led);
+ if (ret < 0)
+ return ret;
+
+ ret = led_classdev_register(&pdev->dev, &cmx270_green_led);
+ if (ret < 0)
+ led_classdev_unregister(&cmx270_red_led);
+
+ return ret;
+}
+
+static int cmx270led_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&cmx270_red_led);
+ led_classdev_unregister(&cmx270_green_led);
+ return 0;
+}
+
+static struct platform_driver cmx270led_driver = {
+ .probe = cmx270led_probe,
+ .remove = cmx270led_remove,
+#ifdef CONFIG_PM
+ .suspend = cmx270led_suspend,
+ .resume = cmx270led_resume,
+#endif
+ .driver = {
+ .name = "cm-x270-led",
+ },
+};
+
+static int __init cmx270led_init(void)
+{
+ return platform_driver_register(&cmx270led_driver);
+}
+
+static void __exit cmx270led_exit(void)
+{
+ platform_driver_unregister(&cmx270led_driver);
+}
+
+module_init(cmx270led_init);
+module_exit(cmx270led_exit);
+
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("CM-x270 LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 657901eecfce..0601e01aa2c2 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -23,6 +23,8 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/mmc/host.h>
#include <asm/dma.h>
@@ -44,6 +46,8 @@ struct pxamci_host {
spinlock_t lock;
struct resource *res;
void __iomem *base;
+ struct clk *clk;
+ unsigned long clkrate;
int irq;
int dma;
unsigned int clkrt;
@@ -119,7 +123,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
writel(nob, host->base + MMC_NOB);
writel(data->blksz, host->base + MMC_BLKLEN);
- clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
+ clks = (unsigned long long)data->timeout_ns * host->clkrate;
do_div(clks, 1000000000UL);
timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
writel((timeout + 255) / 256, host->base + MMC_RDTO);
@@ -365,18 +369,25 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct pxamci_host *host = mmc_priv(mmc);
if (ios->clock) {
- unsigned int clk = CLOCKRATE / ios->clock;
- if (CLOCKRATE / clk > ios->clock)
+ unsigned long rate = host->clkrate;
+ unsigned int clk = rate / ios->clock;
+
+ /*
+ * clk might result in a lower divisor than we
+ * desire. check for that condition and adjust
+ * as appropriate.
+ */
+ if (rate / clk > ios->clock)
clk <<= 1;
host->clkrt = fls(clk) - 1;
- pxa_set_cken(CKEN_MMC, 1);
+ clk_enable(host->clk);
/*
* we write clkrt on the next command
*/
} else {
pxamci_stop_clock(host);
- pxa_set_cken(CKEN_MMC, 0);
+ clk_disable(host->clk);
}
if (host->power_mode != ios->power_mode) {
@@ -462,8 +473,6 @@ static int pxamci_probe(struct platform_device *pdev)
}
mmc->ops = &pxamci_ops;
- mmc->f_min = CLOCKRATE_MIN;
- mmc->f_max = CLOCKRATE_MAX;
/*
* We can do SG-DMA, but we don't because we never know how much
@@ -490,6 +499,22 @@ static int pxamci_probe(struct platform_device *pdev)
host->mmc = mmc;
host->dma = -1;
host->pdata = pdev->dev.platform_data;
+
+ host->clk = clk_get(&pdev->dev, "MMCCLK");
+ if (IS_ERR(host->clk)) {
+ ret = PTR_ERR(host->clk);
+ host->clk = NULL;
+ goto out;
+ }
+
+ host->clkrate = clk_get_rate(host->clk);
+
+ /*
+ * Calculate minimum clock rate, rounding up.
+ */
+ mmc->f_min = (host->clkrate + 63) / 64;
+ mmc->f_max = host->clkrate;
+
mmc->ocr_avail = host->pdata ?
host->pdata->ocr_mask :
MMC_VDD_32_33|MMC_VDD_33_34;
@@ -554,6 +579,8 @@ static int pxamci_probe(struct platform_device *pdev)
iounmap(host->base);
if (host->sg_cpu)
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+ if (host->clk)
+ clk_put(host->clk);
}
if (mmc)
mmc_free_host(mmc);
@@ -588,6 +615,8 @@ static int pxamci_remove(struct platform_device *pdev)
iounmap(host->base);
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+ clk_put(host->clk);
+
release_resource(host->res);
mmc_free_host(mmc);
diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
index 3153e779d46a..748c7706f237 100644
--- a/drivers/mmc/host/pxamci.h
+++ b/drivers/mmc/host/pxamci.h
@@ -88,17 +88,3 @@
#define MMC_RXFIFO 0x0040 /* 8 bit */
#define MMC_TXFIFO 0x0044 /* 8 bit */
-
-/*
- * The base MMC clock rate
- */
-#ifdef CONFIG_PXA27x
-#define CLOCKRATE_MIN 304688
-#define CLOCKRATE_MAX 19500000
-#else
-#define CLOCKRATE_MIN 312500
-#define CLOCKRATE_MAX 20000000
-#endif
-
-#define CLOCKRATE CLOCKRATE_MAX
-
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 55ff0fbe525a..8c09344f58dc 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -23,6 +23,7 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/clk.h>
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
@@ -87,8 +88,30 @@ struct pxa_irda {
struct device *dev;
struct pxaficp_platform_data *pdata;
+ struct clk *fir_clk;
+ struct clk *sir_clk;
+ struct clk *cur_clk;
};
+static inline void pxa_irda_disable_clk(struct pxa_irda *si)
+{
+ if (si->cur_clk)
+ clk_disable(si->cur_clk);
+ si->cur_clk = NULL;
+}
+
+static inline void pxa_irda_enable_firclk(struct pxa_irda *si)
+{
+ si->cur_clk = si->fir_clk;
+ clk_enable(si->fir_clk);
+}
+
+static inline void pxa_irda_enable_sirclk(struct pxa_irda *si)
+{
+ si->cur_clk = si->sir_clk;
+ clk_enable(si->sir_clk);
+}
+
#define IS_FIR(si) ((si)->speed >= 4000000)
#define IRDA_FRAME_SIZE_LIMIT 2047
@@ -134,7 +157,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
DCSR(si->rxdma) &= ~DCSR_RUN;
/* disable FICP */
ICCR0 = 0;
- pxa_set_cken(CKEN_FICP, 0);
+ pxa_irda_disable_clk(si);
/* set board transceiver to SIR mode */
si->pdata->transceiver_mode(si->dev, IR_SIRMODE);
@@ -144,7 +167,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
pxa_gpio_mode(GPIO47_STTXD_MD);
/* enable the STUART clock */
- pxa_set_cken(CKEN_STUART, 1);
+ pxa_irda_enable_sirclk(si);
}
/* disable STUART first */
@@ -169,7 +192,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
/* disable STUART */
STIER = 0;
STISR = 0;
- pxa_set_cken(CKEN_STUART, 0);
+ pxa_irda_disable_clk(si);
/* disable FICP first */
ICCR0 = 0;
@@ -182,7 +205,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
pxa_gpio_mode(GPIO47_ICPTXD_MD);
/* enable the FICP clock */
- pxa_set_cken(CKEN_FICP, 1);
+ pxa_irda_enable_firclk(si);
si->speed = speed;
pxa_irda_fir_dma_rx_start(si);
@@ -592,16 +615,15 @@ static void pxa_irda_shutdown(struct pxa_irda *si)
STIER = 0;
/* disable STUART SIR mode */
STISR = 0;
- /* disable the STUART clock */
- pxa_set_cken(CKEN_STUART, 0);
/* disable DMA */
DCSR(si->txdma) &= ~DCSR_RUN;
DCSR(si->rxdma) &= ~DCSR_RUN;
/* disable FICP */
ICCR0 = 0;
- /* disable the FICP clock */
- pxa_set_cken(CKEN_FICP, 0);
+
+ /* disable the STUART or FICP clocks */
+ pxa_irda_disable_clk(si);
DRCMR17 = 0;
DRCMR18 = 0;
@@ -792,6 +814,13 @@ static int pxa_irda_probe(struct platform_device *pdev)
si->dev = &pdev->dev;
si->pdata = pdev->dev.platform_data;
+ si->sir_clk = clk_get(&pdev->dev, "UARTCLK");
+ si->fir_clk = clk_get(&pdev->dev, "FICPCLK");
+ if (IS_ERR(si->sir_clk) || IS_ERR(si->fir_clk)) {
+ err = PTR_ERR(IS_ERR(si->sir_clk) ? si->sir_clk : si->fir_clk);
+ goto err_mem_4;
+ }
+
/*
* Initialise the SIR buffers
*/
@@ -831,6 +860,10 @@ static int pxa_irda_probe(struct platform_device *pdev)
err_mem_5:
kfree(si->rx_buff.head);
err_mem_4:
+ if (si->sir_clk && !IS_ERR(si->sir_clk))
+ clk_put(si->sir_clk);
+ if (si->fir_clk && !IS_ERR(si->fir_clk))
+ clk_put(si->fir_clk);
free_netdev(dev);
err_mem_3:
release_mem_region(__PREG(FICP), 0x1c);
@@ -850,6 +883,8 @@ static int pxa_irda_remove(struct platform_device *_dev)
unregister_netdev(dev);
kfree(si->tx_buff.head);
kfree(si->rx_buff.head);
+ clk_put(si->fir_clk);
+ clk_put(si->sir_clk);
free_netdev(dev);
}
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 24e610e711e8..7da7589d45dd 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -173,49 +173,6 @@ MODULE_LICENSE("GPL");
*/
#define MII_DELAY 1
-/* store this information for the driver.. */
-struct smc_local {
- /*
- * If I have to wait until memory is available to send a
- * packet, I will store the skbuff here, until I get the
- * desired memory. Then, I'll send it out and free it.
- */
- struct sk_buff *pending_tx_skb;
- struct tasklet_struct tx_task;
-
- /* version/revision of the SMC91x chip */
- int version;
-
- /* Contains the current active transmission mode */
- int tcr_cur_mode;
-
- /* Contains the current active receive mode */
- int rcr_cur_mode;
-
- /* Contains the current active receive/phy mode */
- int rpc_cur_mode;
- int ctl_rfduplx;
- int ctl_rspeed;
-
- u32 msg_enable;
- u32 phy_type;
- struct mii_if_info mii;
-
- /* work queue */
- struct work_struct phy_configure;
- struct net_device *dev;
- int work_pending;
-
- spinlock_t lock;
-
-#ifdef SMC_USE_PXA_DMA
- /* DMA needs the physical address of the chip */
- u_long physaddr;
-#endif
- void __iomem *base;
- void __iomem *datacs;
-};
-
#if SMC_DEBUG > 0
#define DBG(n, args...) \
do { \
@@ -2215,17 +2172,19 @@ static int smc_drv_probe(struct platform_device *pdev)
goto out_release_attrib;
}
- platform_set_drvdata(pdev, ndev);
- ret = smc_probe(ndev, addr);
- if (ret != 0)
- goto out_iounmap;
#ifdef SMC_USE_PXA_DMA
- else {
+ {
struct smc_local *lp = netdev_priv(ndev);
+ lp->device = &pdev->dev;
lp->physaddr = res->start;
}
#endif
+ platform_set_drvdata(pdev, ndev);
+ ret = smc_probe(ndev, addr);
+ if (ret != 0)
+ goto out_iounmap;
+
smc_request_datacs(pdev, ndev);
return 0;
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index af9e6bf59552..729fd28c08b5 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -462,6 +462,52 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
#endif
+
+/* store this information for the driver.. */
+struct smc_local {
+ /*
+ * If I have to wait until memory is available to send a
+ * packet, I will store the skbuff here, until I get the
+ * desired memory. Then, I'll send it out and free it.
+ */
+ struct sk_buff *pending_tx_skb;
+ struct tasklet_struct tx_task;
+
+ /* version/revision of the SMC91x chip */
+ int version;
+
+ /* Contains the current active transmission mode */
+ int tcr_cur_mode;
+
+ /* Contains the current active receive mode */
+ int rcr_cur_mode;
+
+ /* Contains the current active receive/phy mode */
+ int rpc_cur_mode;
+ int ctl_rfduplx;
+ int ctl_rspeed;
+
+ u32 msg_enable;
+ u32 phy_type;
+ struct mii_if_info mii;
+
+ /* work queue */
+ struct work_struct phy_configure;
+ struct net_device *dev;
+ int work_pending;
+
+ spinlock_t lock;
+
+#ifdef SMC_USE_PXA_DMA
+ /* DMA needs the physical address of the chip */
+ u_long physaddr;
+ struct device *device;
+#endif
+ void __iomem *base;
+ void __iomem *datacs;
+};
+
+
#ifdef SMC_USE_PXA_DMA
/*
* Let's use the DMA engine on the XScale PXA2xx for RX packets. This is
@@ -476,11 +522,12 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
#ifdef SMC_insl
#undef SMC_insl
#define SMC_insl(a, r, p, l) \
- smc_pxa_dma_insl(a, lp->physaddr, r, dev->dma, p, l)
+ smc_pxa_dma_insl(a, lp, r, dev->dma, p, l)
static inline void
-smc_pxa_dma_insl(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
+smc_pxa_dma_insl(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
u_char *buf, int len)
{
+ u_long physaddr = lp->physaddr;
dma_addr_t dmabuf;
/* fallback if no DMA available */
@@ -497,7 +544,7 @@ smc_pxa_dma_insl(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
}
len *= 4;
- dmabuf = dma_map_single(NULL, buf, len, DMA_FROM_DEVICE);
+ dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
DCSR(dma) = DCSR_NODESC;
DTADR(dma) = dmabuf;
DSADR(dma) = physaddr + reg;
@@ -507,18 +554,19 @@ smc_pxa_dma_insl(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
while (!(DCSR(dma) & DCSR_STOPSTATE))
cpu_relax();
DCSR(dma) = 0;
- dma_unmap_single(NULL, dmabuf, len, DMA_FROM_DEVICE);
+ dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
}
#endif
#ifdef SMC_insw
#undef SMC_insw
#define SMC_insw(a, r, p, l) \
- smc_pxa_dma_insw(a, lp->physaddr, r, dev->dma, p, l)
+ smc_pxa_dma_insw(a, lp, r, dev->dma, p, l)
static inline void
-smc_pxa_dma_insw(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
+smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
u_char *buf, int len)
{
+ u_long physaddr = lp->physaddr;
dma_addr_t dmabuf;
/* fallback if no DMA available */
@@ -535,7 +583,7 @@ smc_pxa_dma_insw(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
}
len *= 2;
- dmabuf = dma_map_single(NULL, buf, len, DMA_FROM_DEVICE);
+ dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
DCSR(dma) = DCSR_NODESC;
DTADR(dma) = dmabuf;
DSADR(dma) = physaddr + reg;
@@ -545,7 +593,7 @@ smc_pxa_dma_insw(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
while (!(DCSR(dma) & DCSR_STOPSTATE))
cpu_relax();
DCSR(dma) = 0;
- dma_unmap_single(NULL, dmabuf, len, DMA_FROM_DEVICE);
+ dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
}
#endif
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 4276965517f2..dc7a4cb5d270 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -69,4 +69,5 @@ sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o
pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock.o sa1111_generic.o
pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o
pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o
+pxa2xx_cs-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x270.o
diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c
new file mode 100644
index 000000000000..fbf2f3a6984c
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_cm_x270.c
@@ -0,0 +1,175 @@
+/*
+ * linux/drivers/pcmcia/pxa/pxa_cm_x270.c
+ *
+ * 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.
+ *
+ * Compulab Ltd., 2003, 2007
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+
+#include <pcmcia/ss.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/cm-x270.h>
+
+#include "soc_common.h"
+
+static struct pcmcia_irqs irqs[] = {
+ { 0, PCMCIA_S0_CD_VALID, "PCMCIA0 CD" },
+ { 1, PCMCIA_S1_CD_VALID, "PCMCIA1 CD" },
+};
+
+static int cmx270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+ GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+ GPIO_bit(GPIO49_nPWE) |
+ GPIO_bit(GPIO50_nPIOR) |
+ GPIO_bit(GPIO51_nPIOW) |
+ GPIO_bit(GPIO85_nPCE_1) |
+ GPIO_bit(GPIO54_nPCE_2);
+
+ pxa_gpio_mode(GPIO48_nPOE_MD);
+ pxa_gpio_mode(GPIO49_nPWE_MD);
+ pxa_gpio_mode(GPIO50_nPIOR_MD);
+ pxa_gpio_mode(GPIO51_nPIOW_MD);
+ pxa_gpio_mode(GPIO85_nPCE_1_MD);
+ pxa_gpio_mode(GPIO54_nPCE_2_MD);
+ pxa_gpio_mode(GPIO55_nPREG_MD);
+ pxa_gpio_mode(GPIO56_nPWAIT_MD);
+ pxa_gpio_mode(GPIO57_nIOIS16_MD);
+
+ /* Reset signal */
+ pxa_gpio_mode(GPIO53_nPCE_2 | GPIO_OUT);
+ GPCR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+
+ set_irq_type(PCMCIA_S0_CD_VALID, IRQ_TYPE_EDGE_BOTH);
+ set_irq_type(PCMCIA_S1_CD_VALID, IRQ_TYPE_EDGE_BOTH);
+
+ /* irq's for slots: */
+ set_irq_type(PCMCIA_S0_RDYINT, IRQ_TYPE_EDGE_FALLING);
+ set_irq_type(PCMCIA_S1_RDYINT, IRQ_TYPE_EDGE_FALLING);
+
+ skt->irq = (skt->nr == 0) ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT;
+ return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+}
+
+static void cmx270_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
+{
+ soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+
+ set_irq_type(IRQ_TO_GPIO(PCMCIA_S0_CD_VALID), IRQ_TYPE_NONE);
+ set_irq_type(IRQ_TO_GPIO(PCMCIA_S1_CD_VALID), IRQ_TYPE_NONE);
+
+ set_irq_type(IRQ_TO_GPIO(PCMCIA_S0_RDYINT), IRQ_TYPE_NONE);
+ set_irq_type(IRQ_TO_GPIO(PCMCIA_S1_RDYINT), IRQ_TYPE_NONE);
+}
+
+
+static void cmx270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+ struct pcmcia_state *state)
+{
+ state->detect = (PCC_DETECT(skt->nr) == 0) ? 1 : 0;
+ state->ready = (PCC_READY(skt->nr) == 0) ? 0 : 1;
+ state->bvd1 = 1;
+ state->bvd2 = 1;
+ state->vs_3v = 0;
+ state->vs_Xv = 0;
+ state->wrprot = 0; /* not available */
+}
+
+
+static int cmx270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+ const socket_state_t *state)
+{
+ GPSR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ pxa_gpio_mode(GPIO49_nPWE | GPIO_OUT);
+
+ switch (skt->nr) {
+ case 0:
+ if (state->flags & SS_RESET) {
+ GPCR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ GPSR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+ udelay(10);
+ GPCR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+ GPSR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ }
+ break;
+ case 1:
+ if (state->flags & SS_RESET) {
+ GPCR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ GPSR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+ udelay(10);
+ GPCR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+ GPSR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ }
+ break;
+ }
+
+ pxa_gpio_mode(GPIO49_nPWE_MD);
+
+ return 0;
+}
+
+static void cmx270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+}
+
+static void cmx270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+}
+
+
+static struct pcmcia_low_level cmx270_pcmcia_ops = {
+ .owner = THIS_MODULE,
+ .hw_init = cmx270_pcmcia_hw_init,
+ .hw_shutdown = cmx270_pcmcia_shutdown,
+ .socket_state = cmx270_pcmcia_socket_state,
+ .configure_socket = cmx270_pcmcia_configure_socket,
+ .socket_init = cmx270_pcmcia_socket_init,
+ .socket_suspend = cmx270_pcmcia_socket_suspend,
+ .nr = 2,
+};
+
+static struct platform_device *cmx270_pcmcia_device;
+
+static int __init cmx270_pcmcia_init(void)
+{
+ int ret;
+
+ cmx270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+
+ if (!cmx270_pcmcia_device)
+ return -ENOMEM;
+
+ cmx270_pcmcia_device->dev.platform_data = &cmx270_pcmcia_ops;<