diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2007-10-15 18:55:44 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-10-15 18:56:02 +0100 |
commit | 0181b61a988424b5cc44fe09e6968142359c815e (patch) | |
tree | 2575ee900a39ffaa169ad5aeb8aa6ddee11cfbe5 /drivers | |
parent | 92633b72d18ca4f25de1f28e436a882159491e7e (diff) | |
parent | 87944f3361fc033b73617aa663135c6e468957a7 (diff) |
Merge branch 'pxa' into devel
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 45 | ||||
-rw-r--r-- | drivers/input/keyboard/pxa27x_keyboard.c | 25 | ||||
-rw-r--r-- | drivers/leds/Kconfig | 6 | ||||
-rw-r--r-- | drivers/leds/Makefile | 1 | ||||
-rw-r--r-- | drivers/leds/leds-cm-x270.c | 122 | ||||
-rw-r--r-- | drivers/mmc/host/pxamci.c | 43 | ||||
-rw-r--r-- | drivers/mmc/host/pxamci.h | 14 | ||||
-rw-r--r-- | drivers/net/irda/pxaficp_ir.c | 51 | ||||
-rw-r--r-- | drivers/net/smc91x.c | 55 | ||||
-rw-r--r-- | drivers/net/smc91x.h | 64 | ||||
-rw-r--r-- | drivers/pcmcia/Makefile | 1 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_cm_x270.c | 175 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_lubbock.c | 31 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_mainstone.c | 18 | ||||
-rw-r--r-- | drivers/serial/pxa.c | 163 | ||||
-rw-r--r-- | drivers/serial/serial_core.c | 18 | ||||
-rw-r--r-- | drivers/usb/gadget/pxa2xx_udc.c | 68 | ||||
-rw-r--r-- | drivers/usb/gadget/pxa2xx_udc.h | 1 | ||||
-rw-r--r-- | drivers/video/pxafb.c | 36 | ||||
-rw-r--r-- | drivers/video/pxafb.h | 1 |
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;< |