diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 14:39:22 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 14:39:22 -0800 |
commit | 2ac9d7aaccbd598b5bd19ac40761b723bb675442 (patch) | |
tree | 09132a44e33798aaa5e80f10bf025b510015cab3 /drivers | |
parent | 5ede3ceb7b2c2843e153a1803edbdc8c56655950 (diff) | |
parent | dcf7ec5ee62a78123057a1e286c88ca739717409 (diff) | |
download | linux-2ac9d7aaccbd598b5bd19ac40761b723bb675442.tar.bz2 |
Merge tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Driver specific changes
Again, a lot of platforms have changes in here: pxa, samsung, omap,
at91, imx, ...
* tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (54 commits)
ARM: sa1100: clean up of the clock support
ARM: pxa: add dummy clock for sa1100-rtc
RTC: sa1100: support sa1100, pxa and mmp soc families
RTC: sa1100: remove redundant code of setting alarm
RTC: sa1100: Clean out ost register
Input: zylonite-wm97xx - replace IRQ_GPIO() with gpio_to_irq()
pcmcia: pxa: replace IRQ_GPIO() with gpio_to_irq()
ARM: EXYNOS: Modified files for SPI consolidation work
ARM: S5P64X0: Enable SDHCI support
ARM: S5P64X0: Add lookup of sdhci-s3c clocks using generic names
ARM: S5P64X0: Add HSMMC setup for host Controller
ARM: EXYNOS: Add USB OHCI support to ORIGEN board
USB: Add Samsung Exynos OHCI diver
ARM: EXYNOS: Add USB OHCI support to SMDKV310 board
ARM: EXYNOS: Add USB OHCI device
net: macb: fix build break with !CONFIG_OF
i2c: tegra: Support DVC controller in device tree
i2c: tegra: Add __devinit/exit to probe/remove
net/at91_ether: use gpio_is_valid for phy IRQ line
ARM: at91/net: add macb ethernet controller in 9g45/9g20 DT
...
Diffstat (limited to 'drivers')
28 files changed, 1581 insertions, 740 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5099681cf503..e3380137b05b 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -141,6 +141,12 @@ config GPIO_PL061 help Say yes here to support the PrimeCell PL061 GPIO device +config GPIO_PXA + bool "PXA GPIO support" + depends on ARCH_PXA || ARCH_MMP + help + Say yes here to support the PXA GPIO device + config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4e018d6a7639..8ef9e9abe970 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -40,7 +40,7 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o -obj-$(CONFIG_PLAT_PXA) += gpio-pxa.o +obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index ee137712f9db..b2d3ee1d183a 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -11,14 +11,46 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <linux/clk.h> +#include <linux/err.h> #include <linux/gpio.h> +#include <linux/gpio-pxa.h> #include <linux/init.h> #include <linux/irq.h> #include <linux/io.h> +#include <linux/platform_device.h> #include <linux/syscore_ops.h> #include <linux/slab.h> -#include <mach/gpio-pxa.h> +/* + * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with + * one set of registers. The register offsets are organized below: + * + * GPLR GPDR GPSR GPCR GRER GFER GEDR + * BANK 0 - 0x0000 0x000C 0x0018 0x0024 0x0030 0x003C 0x0048 + * BANK 1 - 0x0004 0x0010 0x001C 0x0028 0x0034 0x0040 0x004C + * BANK 2 - 0x0008 0x0014 0x0020 0x002C 0x0038 0x0044 0x0050 + * + * BANK 3 - 0x0100 0x010C 0x0118 0x0124 0x0130 0x013C 0x0148 + * BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C + * BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150 + * + * NOTE: + * BANK 3 is only available on PXA27x and later processors. + * BANK 4 and 5 are only available on PXA935 + */ + +#define GPLR_OFFSET 0x00 +#define GPDR_OFFSET 0x0C +#define GPSR_OFFSET 0x18 +#define GPCR_OFFSET 0x24 +#define GRER_OFFSET 0x30 +#define GFER_OFFSET 0x3C +#define GEDR_OFFSET 0x48 +#define GAFR_OFFSET 0x54 +#define ED_MASK_OFFSET 0x9C /* GPIO edge detection for AP side */ + +#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) int pxa_last_gpio; @@ -39,8 +71,20 @@ struct pxa_gpio_chip { #endif }; +enum { + PXA25X_GPIO = 0, + PXA26X_GPIO, + PXA27X_GPIO, + PXA3XX_GPIO, + PXA93X_GPIO, + MMP_GPIO = 0x10, + MMP2_GPIO, +}; + static DEFINE_SPINLOCK(gpio_lock); static struct pxa_gpio_chip *pxa_gpio_chips; +static int gpio_type; +static void __iomem *gpio_reg_base; #define for_each_gpio_chip(i, c) \ for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++) @@ -55,6 +99,122 @@ static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio) return &pxa_gpio_chips[gpio_to_bank(gpio)]; } +static inline int gpio_is_pxa_type(int type) +{ + return (type & MMP_GPIO) == 0; +} + +static inline int gpio_is_mmp_type(int type) +{ + return (type & MMP_GPIO) != 0; +} + +/* GPIO86/87/88/89 on PXA26x have their direction bits in PXA_GPDR(2 inverted, + * as well as their Alternate Function value being '1' for GPIO in GAFRx. + */ +static inline int __gpio_is_inverted(int gpio) +{ + if ((gpio_type == PXA26X_GPIO) && (gpio > 85)) + return 1; + return 0; +} + +/* + * On PXA25x and PXA27x, GAFRx and GPDRx together decide the alternate + * function of a GPIO, and GPDRx cannot be altered once configured. It + * is attributed as "occupied" here (I know this terminology isn't + * accurate, you are welcome to propose a better one :-) + */ +static inline int __gpio_is_occupied(unsigned gpio) +{ + struct pxa_gpio_chip *pxachip; + void __iomem *base; + unsigned long gafr = 0, gpdr = 0; + int ret, af = 0, dir = 0; + + pxachip = gpio_to_pxachip(gpio); + base = gpio_chip_base(&pxachip->chip); + gpdr = readl_relaxed(base + GPDR_OFFSET); + + switch (gpio_type) { + case PXA25X_GPIO: + case PXA26X_GPIO: + case PXA27X_GPIO: + gafr = readl_relaxed(base + GAFR_OFFSET); + af = (gafr >> ((gpio & 0xf) * 2)) & 0x3; + dir = gpdr & GPIO_bit(gpio); + + if (__gpio_is_inverted(gpio)) + ret = (af != 1) || (dir == 0); + else + ret = (af != 0) || (dir != 0); + break; + default: + ret = gpdr & GPIO_bit(gpio); + break; + } + return ret; +} + +#ifdef CONFIG_ARCH_PXA +static inline int __pxa_gpio_to_irq(int gpio) +{ + if (gpio_is_pxa_type(gpio_type)) + return PXA_GPIO_TO_IRQ(gpio); + return -1; +} + +static inline int __pxa_irq_to_gpio(int irq) +{ + if (gpio_is_pxa_type(gpio_type)) + return irq - PXA_GPIO_TO_IRQ(0); + return -1; +} +#else +static inline int __pxa_gpio_to_irq(int gpio) { return -1; } +static inline int __pxa_irq_to_gpio(int irq) { return -1; } +#endif + +#ifdef CONFIG_ARCH_MMP +static inline int __mmp_gpio_to_irq(int gpio) +{ + if (gpio_is_mmp_type(gpio_type)) + return MMP_GPIO_TO_IRQ(gpio); + return -1; +} + +static inline int __mmp_irq_to_gpio(int irq) +{ + if (gpio_is_mmp_type(gpio_type)) + return irq - MMP_GPIO_TO_IRQ(0); + return -1; +} +#else +static inline int __mmp_gpio_to_irq(int gpio) { return -1; } +static inline int __mmp_irq_to_gpio(int irq) { return -1; } +#endif + +static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + int gpio, ret; + + gpio = chip->base + offset; + ret = __pxa_gpio_to_irq(gpio); + if (ret >= 0) + return ret; + return __mmp_gpio_to_irq(gpio); +} + +int pxa_irq_to_gpio(int irq) +{ + int ret; + + ret = __pxa_irq_to_gpio(irq); + if (ret >= 0) + return ret; + return __mmp_irq_to_gpio(irq); +} + static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { void __iomem *base = gpio_chip_base(chip); @@ -63,12 +223,12 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&gpio_lock, flags); - value = __raw_readl(base + GPDR_OFFSET); + value = readl_relaxed(base + GPDR_OFFSET); if (__gpio_is_inverted(chip->base + offset)) value |= mask; else value &= ~mask; - __raw_writel(value, base + GPDR_OFFSET); + writel_relaxed(value, base + GPDR_OFFSET); spin_unlock_irqrestore(&gpio_lock, flags); return 0; @@ -81,16 +241,16 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip, uint32_t tmp, mask = 1 << offset; unsigned long flags; - __raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); + writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); spin_lock_irqsave(&gpio_lock, flags); - tmp = __raw_readl(base + GPDR_OFFSET); + tmp = readl_relaxed(base + GPDR_OFFSET); if (__gpio_is_inverted(chip->base + offset)) tmp &= ~mask; else tmp |= mask; - __raw_writel(tmp, base + GPDR_OFFSET); + writel_relaxed(tmp, base + GPDR_OFFSET); spin_unlock_irqrestore(&gpio_lock, flags); return 0; @@ -98,16 +258,16 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip, static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) { - return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset); + return readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset); } static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - __raw_writel(1 << offset, gpio_chip_base(chip) + + writel_relaxed(1 << offset, gpio_chip_base(chip) + (value ? GPSR_OFFSET : GPCR_OFFSET)); } -static int __init pxa_init_gpio_chip(int gpio_end) +static int __devinit pxa_init_gpio_chip(int gpio_end) { int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1; struct pxa_gpio_chip *chips; @@ -122,7 +282,7 @@ static int __init pxa_init_gpio_chip(int gpio_end) struct gpio_chip *c = &chips[i].chip; sprintf(chips[i].label, "gpio-%d", i); - chips[i].regbase = GPIO_BANK(i); + chips[i].regbase = gpio_reg_base + BANK_OFF(i); c->base = gpio; c->label = chips[i].label; @@ -131,6 +291,7 @@ static int __init pxa_init_gpio_chip(int gpio_end) c->direction_output = pxa_gpio_direction_output; c->get = pxa_gpio_get; c->set = pxa_gpio_set; + c->to_irq = pxa_gpio_to_irq; /* number of GPIOs on last bank may be less than 32 */ c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32; @@ -147,18 +308,18 @@ static inline void update_edge_detect(struct pxa_gpio_chip *c) { uint32_t grer, gfer; - grer = __raw_readl(c->regbase + GRER_OFFSET) & ~c->irq_mask; - gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~c->irq_mask; + grer = readl_relaxed(c->regbase + GRER_OFFSET) & ~c->irq_mask; + gfer = readl_relaxed(c->regbase + GFER_OFFSET) & ~c->irq_mask; grer |= c->irq_edge_rise & c->irq_mask; gfer |= c->irq_edge_fall & c->irq_mask; - __raw_writel(grer, c->regbase + GRER_OFFSET); - __raw_writel(gfer, c->regbase + GFER_OFFSET); + writel_relaxed(grer, c->regbase + GRER_OFFSET); + writel_relaxed(gfer, c->regbase + GFER_OFFSET); } static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) { struct pxa_gpio_chip *c; - int gpio = irq_to_gpio(d->irq); + int gpio = pxa_irq_to_gpio(d->irq); unsigned long gpdr, mask = GPIO_bit(gpio); c = gpio_to_pxachip(gpio); @@ -176,12 +337,12 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; } - gpdr = __raw_readl(c->regbase + GPDR_OFFSET); + gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); if (__gpio_is_inverted(gpio)) - __raw_writel(gpdr | mask, c->regbase + GPDR_OFFSET); + writel_relaxed(gpdr | mask, c->regbase + GPDR_OFFSET); else - __raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET); + writel_relaxed(gpdr & ~mask, c->regbase + GPDR_OFFSET); if (type & IRQ_TYPE_EDGE_RISING) c->irq_edge_rise |= mask; @@ -212,9 +373,9 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) for_each_gpio_chip(gpio, c) { gpio_base = c->chip.base; - gedr = __raw_readl(c->regbase + GEDR_OFFSET); + gedr = readl_relaxed(c->regbase + GEDR_OFFSET); gedr = gedr & c->irq_mask; - __raw_writel(gedr, c->regbase + GEDR_OFFSET); + writel_relaxed(gedr, c->regbase + GEDR_OFFSET); n = find_first_bit(&gedr, BITS_PER_LONG); while (n < BITS_PER_LONG) { @@ -229,29 +390,29 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) static void pxa_ack_muxed_gpio(struct irq_data *d) { - int gpio = irq_to_gpio(d->irq); + int gpio = pxa_irq_to_gpio(d->irq); struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); - __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET); + writel_relaxed(GPIO_bit(gpio), c->regbase + GEDR_OFFSET); } static void pxa_mask_muxed_gpio(struct irq_data *d) { - int gpio = irq_to_gpio(d->irq); + int gpio = pxa_irq_to_gpio(d->irq); struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); uint32_t grer, gfer; c->irq_mask &= ~GPIO_bit(gpio); - grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio); - gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio); - __raw_writel(grer, c->regbase + GRER_OFFSET); - __raw_writel(gfer, c->regbase + GFER_OFFSET); + grer = readl_relaxed(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio); + gfer = readl_relaxed(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio); + writel_relaxed(grer, c->regbase + GRER_OFFSET); + writel_relaxed(gfer, c->regbase + GFER_OFFSET); } static void pxa_unmask_muxed_gpio(struct irq_data *d) { - int gpio = irq_to_gpio(d->irq); + int gpio = pxa_irq_to_gpio(d->irq); struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); c->irq_mask |= GPIO_bit(gpio); @@ -266,34 +427,143 @@ static struct irq_chip pxa_muxed_gpio_chip = { .irq_set_type = pxa_gpio_irq_type, }; -void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn) +static int pxa_gpio_nums(void) { - struct pxa_gpio_chip *c; - int gpio, irq; + int count = 0; + +#ifdef CONFIG_ARCH_PXA + if (cpu_is_pxa25x()) { +#ifdef CONFIG_CPU_PXA26x + count = 89; + gpio_type = PXA26X_GPIO; +#elif defined(CONFIG_PXA25x) + count = 84; + gpio_type = PXA26X_GPIO; +#endif /* CONFIG_CPU_PXA26x */ + } else if (cpu_is_pxa27x()) { + count = 120; + gpio_type = PXA27X_GPIO; + } else if (cpu_is_pxa93x() || cpu_is_pxa95x()) { + count = 191; + gpio_type = PXA93X_GPIO; + } else if (cpu_is_pxa3xx()) { + count = 127; + gpio_type = PXA3XX_GPIO; + } +#endif /* CONFIG_ARCH_PXA */ + +#ifdef CONFIG_ARCH_MMP + if (cpu_is_pxa168() || cpu_is_pxa910()) { + count = 127; + gpio_type = MMP_GPIO; + } else if (cpu_is_mmp2()) { + count = 191; + gpio_type = MMP2_GPIO; + } +#endif /* CONFIG_ARCH_MMP */ + return count; +} - pxa_last_gpio = end; +static int __devinit pxa_gpio_probe(struct platform_device *pdev) +{ + struct pxa_gpio_chip *c; + struct resource *res; + struct clk *clk; + int gpio, irq, ret; + int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0; + + pxa_last_gpio = pxa_gpio_nums(); + if (!pxa_last_gpio) + return -EINVAL; + + irq0 = platform_get_irq_byname(pdev, "gpio0"); + irq1 = platform_get_irq_byname(pdev, "gpio1"); + irq_mux = platform_get_irq_byname(pdev, "gpio_mux"); + if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0) + || (irq_mux <= 0)) + return -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + gpio_reg_base = ioremap(res->start, resource_size(res)); + if (!gpio_reg_base) + return -EINVAL; + + if (irq0 > 0) + gpio_offset = 2; + + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Error %ld to get gpio clock\n", + PTR_ERR(clk)); + iounmap(gpio_reg_base); + return PTR_ERR(clk); + } + ret = clk_prepare(clk); + if (ret) { + clk_put(clk); + iounmap(gpio_reg_base); + return ret; + } + ret = clk_enable(clk); + if (ret) { + clk_unprepare(clk); + clk_put(clk); + iounmap(gpio_reg_base); + return ret; + } /* Initialize GPIO chips */ - pxa_init_gpio_chip(end); + pxa_init_gpio_chip(pxa_last_gpio); /* clear all GPIO edge detects */ for_each_gpio_chip(gpio, c) { - __raw_writel(0, c->regbase + GFER_OFFSET); - __raw_writel(0, c->regbase + GRER_OFFSET); - __raw_writel(~0,c->regbase + GEDR_OFFSET); + writel_relaxed(0, c->regbase + GFER_OFFSET); + writel_relaxed(0, c->regbase + GRER_OFFSET); + writel_relaxed(~0,c->regbase + GEDR_OFFSET); + /* unmask GPIO edge detect for AP side */ + if (gpio_is_mmp_type(gpio_type)) + writel_relaxed(~0, c->regbase + ED_MASK_OFFSET); } - for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) { +#ifdef CONFIG_ARCH_PXA + irq = gpio_to_irq(0); + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler); + + irq = gpio_to_irq(1); + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler); +#endif + + for (irq = gpio_to_irq(gpio_offset); + irq <= gpio_to_irq(pxa_last_gpio); irq++) { irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - /* Install handler for GPIO>=2 edge detect interrupts */ - irq_set_chained_handler(mux_irq, pxa_gpio_demux_handler); - pxa_muxed_gpio_chip.irq_set_wake = fn; + irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler); + return 0; } +static struct platform_driver pxa_gpio_driver = { + .probe = pxa_gpio_probe, + .driver = { + .name = "pxa-gpio", + }, +}; + +static int __init pxa_gpio_init(void) +{ + return platform_driver_register(&pxa_gpio_driver); +} +postcore_initcall(pxa_gpio_init); + #ifdef CONFIG_PM static int pxa_gpio_suspend(void) { @@ -301,13 +571,13 @@ static int pxa_gpio_suspend(void) int gpio; for_each_gpio_chip(gpio, c) { - c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET); - c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET); - c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET); - c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET); + c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET); + c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); + c->saved_grer = readl_relaxed(c->regbase + GRER_OFFSET); + c->saved_gfer = readl_relaxed(c->regbase + GFER_OFFSET); /* Clear GPIO transition detect bits */ - __raw_writel(0xffffffff, c->regbase + GEDR_OFFSET); + writel_relaxed(0xffffffff, c->regbase + GEDR_OFFSET); } return 0; } @@ -319,12 +589,12 @@ static void pxa_gpio_resume(void) for_each_gpio_chip(gpio, c) { /* restore level with set/clear */ - __raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET); - __raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET); + writel_relaxed( c->saved_gplr, c->regbase + GPSR_OFFSET); + writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET); - __raw_writel(c->saved_grer, c->regbase + GRER_OFFSET); - __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET); - __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET); + writel_relaxed(c->saved_grer, c->regbase + GRER_OFFSET); + writel_relaxed(c->saved_gfer, c->regbase + GFER_OFFSET); + writel_relaxed(c->saved_gpdr, c->regbase + GPDR_OFFSET); } } #else @@ -336,3 +606,10 @@ struct syscore_ops pxa_gpio_syscore_ops = { .suspend = pxa_gpio_suspend, .resume = pxa_gpio_resume, }; + +static int __init pxa_gpio_sysinit(void) +{ + register_syscore_ops(&pxa_gpio_syscore_ops); + return 0; +} +postcore_initcall(pxa_gpio_sysinit); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 46b6500c5478..6381604696d3 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -558,7 +558,7 @@ static const struct i2c_algorithm tegra_i2c_algo = { .functionality = tegra_i2c_func, }; -static int tegra_i2c_probe(struct platform_device *pdev) +static int __devinit tegra_i2c_probe(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev; struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data; @@ -636,7 +636,10 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->bus_clk_rate = be32_to_cpup(prop); } - if (pdev->id == 3) + if (pdev->dev.of_node) + i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, + "nvidia,tegra20-i2c-dvc"); + else if (pdev->id == 3) i2c_dev->is_dvc = 1; init_completion(&i2c_dev->msg_complete); @@ -690,7 +693,7 @@ err_iounmap: return ret; } -static int tegra_i2c_remove(struct platform_device *pdev) +static int __devexit tegra_i2c_remove(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); i2c_del_adapter(&i2c_dev->adapter); @@ -742,6 +745,7 @@ static int tegra_i2c_resume(struct platform_device *pdev) /* Match table for of_platform binding */ static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { { .compatible = "nvidia,tegra20-i2c", }, + { .compatible = "nvidia,tegra20-i2c-dvc", }, {}, }; MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c index f6328c0cded6..0a707bbbbea6 100644 --- a/drivers/input/touchscreen/zylonite-wm97xx.c +++ b/drivers/input/touchscreen/zylonite-wm97xx.c @@ -22,6 +22,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/gpio.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -192,8 +193,8 @@ static int zylonite_wm97xx_probe(struct platform_device *pdev) else gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26); - wm->pen_irq = IRQ_GPIO(gpio_touch_irq); - irq_set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH); + wm->pen_irq = gpio_to_irq(gpio_touch_irq); + irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, WM97XX_GPIO_POL_HIGH, diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 86e14583a082..3f565ef3e149 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -27,8 +27,9 @@ #include <linux/spinlock.h> #include <linux/gpio.h> #include <plat/usb.h> +#include <linux/pm_runtime.h> -#define USBHS_DRIVER_NAME "usbhs-omap" +#define USBHS_DRIVER_NAME "usbhs_omap" #define OMAP_EHCI_DEVICE "ehci-omap" #define OMAP_OHCI_DEVICE "ohci-omap3" @@ -147,9 +148,6 @@ struct usbhs_hcd_omap { - struct clk *usbhost_ick; - struct clk *usbhost_hs_fck; - struct clk *usbhost_fs_fck; struct clk *xclk60mhsp1_ck; struct clk *xclk60mhsp2_ck; struct clk *utmi_p1_fck; @@ -159,8 +157,7 @@ struct usbhs_hcd_omap { struct clk *usbhost_p2_fck; struct clk *usbtll_p2_fck; struct clk *init_60m_fclk; - struct clk *usbtll_fck; - struct clk *usbtll_ick; + struct clk *ehci_logic_fck; void __iomem *uhh_base; void __iomem *tll_base; @@ -169,7 +166,6 @@ struct usbhs_hcd_omap { u32 usbhs_rev; spinlock_t lock; - int count; }; /*-------------------------------------------------------------------------*/ @@ -319,269 +315,6 @@ err_end: return ret; } -/** - * usbhs_omap_probe - initialize TI-based HCDs - * - * Allocates basic resources for this USB host controller. - */ -static int __devinit usbhs_omap_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usbhs_omap_platform_data *pdata = dev->platform_data; - struct usbhs_hcd_omap *omap; - struct resource *res; - int ret = 0; - int i; - - if (!pdata) { - dev_err(dev, "Missing platform data\n"); - ret = -ENOMEM; - goto end_probe; - } - - omap = kzalloc(sizeof(*omap), GFP_KERNEL); - if (!omap) { - dev_err(dev, "Memory allocation failed\n"); - ret = -ENOMEM; - goto end_probe; - } - - spin_lock_init(&omap->lock); - - for (i = 0; i < OMAP3_HS_USB_PORTS; i++) - omap->platdata.port_mode[i] = pdata->port_mode[i]; - - omap->platdata.ehci_data = pdata->ehci_data; - omap->platdata.ohci_data = pdata->ohci_data; - - omap->usbhost_ick = clk_get(dev, "usbhost_ick"); - if (IS_ERR(omap->usbhost_ick)) { - ret = PTR_ERR(omap->usbhost_ick); - dev_err(dev, "usbhost_ick failed error:%d\n", ret); - goto err_end; - } - - omap->usbhost_hs_fck = clk_get(dev, "hs_fck"); - if (IS_ERR(omap->usbhost_hs_fck)) { - ret = PTR_ERR(omap->usbhost_hs_fck); - dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret); - goto err_usbhost_ick; - } - - omap->usbhost_fs_fck = clk_get(dev, "fs_fck"); - if (IS_ERR(omap->usbhost_fs_fck)) { - ret = PTR_ERR(omap->usbhost_fs_fck); - dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret); - goto err_usbhost_hs_fck; - } - - omap->usbtll_fck = clk_get(dev, "usbtll_fck"); - if (IS_ERR(omap->usbtll_fck)) { - ret = PTR_ERR(omap->usbtll_fck); - dev_err(dev, "usbtll_fck failed error:%d\n", ret); - goto err_usbhost_fs_fck; - } - - omap->usbtll_ick = clk_get(dev, "usbtll_ick"); - if (IS_ERR(omap->usbtll_ick)) { - ret = PTR_ERR(omap->usbtll_ick); - dev_err(dev, "usbtll_ick failed error:%d\n", ret); - goto err_usbtll_fck; - } - - omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); - if (IS_ERR(omap->utmi_p1_fck)) { - ret = PTR_ERR(omap->utmi_p1_fck); - dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); - goto err_usbtll_ick; - } - - omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); - if (IS_ERR(omap->xclk60mhsp1_ck)) { - ret = PTR_ERR(omap->xclk60mhsp1_ck); - dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); - goto err_utmi_p1_fck; - } - - omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk"); - if (IS_ERR(omap->utmi_p2_fck)) { - ret = PTR_ERR(omap->utmi_p2_fck); - dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); - goto err_xclk60mhsp1_ck; - } - - omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); - if (IS_ERR(omap->xclk60mhsp2_ck)) { - ret = PTR_ERR(omap->xclk60mhsp2_ck); - dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); - goto err_utmi_p2_fck; - } - - omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk"); - if (IS_ERR(omap->usbhost_p1_fck)) { - ret = PTR_ERR(omap->usbhost_p1_fck); - dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret); - goto err_xclk60mhsp2_ck; - } - - omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); - if (IS_ERR(omap->usbtll_p1_fck)) { - ret = PTR_ERR(omap->usbtll_p1_fck); - dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); - goto err_usbhost_p1_fck; - } - - omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); - if (IS_ERR(omap->usbhost_p2_fck)) { - ret = PTR_ERR(omap->usbhost_p2_fck); - dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); - goto err_usbtll_p1_fck; - } - - omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); - if (IS_ERR(omap->usbtll_p2_fck)) { - ret = PTR_ERR(omap->usbtll_p2_fck); - dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); - goto err_usbhost_p2_fck; - } - - omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); - if (IS_ERR(omap->init_60m_fclk)) { - ret = PTR_ERR(omap->init_60m_fclk); - dev_err(dev, "init_60m_fclk failed error:%d\n", ret); - goto err_usbtll_p2_fck; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); - if (!res) { - dev_err(dev, "UHH EHCI get resource failed\n"); - ret = -ENODEV; - goto err_init_60m_fclk; - } - - omap->uhh_base = ioremap(res->start, resource_size(res)); - if (!omap->uhh_base) { - dev_err(dev, "UHH ioremap failed\n"); - ret = -ENOMEM; - goto err_init_60m_fclk; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); - if (!res) { - dev_err(dev, "UHH EHCI get resource failed\n"); - ret = -ENODEV; - goto err_tll; - } - - omap->tll_base = ioremap(res->start, resource_size(res)); - if (!omap->tll_base) { - dev_err(dev, "TLL ioremap failed\n"); - ret = -ENOMEM; - goto err_tll; - } - - platform_set_drvdata(pdev, omap); - - ret = omap_usbhs_alloc_children(pdev); - if (ret) { - dev_err(dev, "omap_usbhs_alloc_children failed\n"); - goto err_alloc; - } - - goto end_probe; - -err_alloc: - iounmap(omap->tll_base); - -err_tll: - iounmap(omap->uhh_base); - -err_init_60m_fclk: - clk_put(omap->init_60m_fclk); - -err_usbtll_p2_fck: - clk_put(omap->usbtll_p2_fck); - -err_usbhost_p2_fck: - clk_put(omap->usbhost_p2_fck); - -err_usbtll_p1_fck: - clk_put(omap->usbtll_p1_fck); - -err_usbhost_p1_fck: - clk_put(omap->usbhost_p1_fck); - -err_xclk60mhsp2_ck: - clk_put(omap->xclk60mhsp2_ck); - -err_utmi_p2_fck: - clk_put(omap->utmi_p2_fck); - -err_xclk60mhsp1_ck: - clk_put(omap->xclk60mhsp1_ck); - -err_utmi_p1_fck: - clk_put(omap->utmi_p1_fck); - -err_usbtll_ick: - clk_put(omap->usbtll_ick); - -err_usbtll_fck: - clk_put(omap->usbtll_fck); - -err_usbhost_fs_fck: - clk_put(omap->usbhost_fs_fck); - -err_usbhost_hs_fck: - clk_put(omap->usbhost_hs_fck); - -err_usbhost_ick: - clk_put(omap->usbhost_ick); - -err_end: - kfree(omap); - -end_probe: - return ret; -} - -/** - * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs - * @pdev: USB Host Controller being removed - * - * Reverses the effect of usbhs_omap_probe(). - */ -static int __devexit usbhs_omap_remove(struct platform_device *pdev) -{ - struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); - - if (omap->count != 0) { - dev_err(&pdev->dev, - "Either EHCI or OHCI is still using usbhs core\n"); - return -EBUSY; - } - - iounmap(omap->tll_base); - iounmap(omap->uhh_base); - clk_put(omap->init_60m_fclk); - clk_put(omap->usbtll_p2_fck); - clk_put(omap->usbhost_p2_fck); - clk_put(omap->usbtll_p1_fck); - clk_put(omap->usbhost_p1_fck); - clk_put(omap->xclk60mhsp2_ck); - clk_put(omap->utmi_p2_fck); - clk_put(omap->xclk60mhsp1_ck); - clk_put(omap->utmi_p1_fck); - clk_put(omap->usbtll_ick); - clk_put(omap->usbtll_fck); - clk_put(omap->usbhost_fs_fck); - clk_put(omap->usbhost_hs_fck); - clk_put(omap->usbhost_ick); - kfree(omap); - - return 0; -} - static bool is_ohci_port(enum usbhs_omap_port_mode pmode) { switch (pmode) { @@ -689,30 +422,85 @@ static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count) } } -static int usbhs_enable(struct device *dev) +static int usbhs_runtime_resume(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); struct usbhs_omap_platform_data *pdata = &omap->platdata; - unsigned long flags = 0; - int ret = 0; - unsigned long timeout; - unsigned reg; + unsigned long flags; + + dev_dbg(dev, "usbhs_runtime_resume\n"); - dev_dbg(dev, "starting TI HSUSB Controller\n"); if (!pdata) { dev_dbg(dev, "missing platform_data\n"); return -ENODEV; } spin_lock_irqsave(&omap->lock, flags); - if (omap->count > 0) - goto end_count; - clk_enable(omap->usbhost_ick); - clk_enable(omap->usbhost_hs_fck); - clk_enable(omap->usbhost_fs_fck); - clk_enable(omap->usbtll_fck); - clk_enable(omap->usbtll_ick); + if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) + clk_enable(omap->ehci_logic_fck); + + if (is_ehci_tll_mode(pdata->port_mode[0])) { + clk_enable(omap->usbhost_p1_fck); + clk_enable(omap->usbtll_p1_fck); + } + if (is_ehci_tll_mode(pdata->port_mode[1])) { + clk_enable(omap->usbhost_p2_fck); + clk_enable(omap->usbtll_p2_fck); + } + clk_enable(omap->utmi_p1_fck); + clk_enable(omap->utmi_p2_fck); + + spin_unlock_irqrestore(&omap->lock, flags); + + return 0; +} + +static int usbhs_runtime_suspend(struct device *dev) +{ + struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); + struct usbhs_omap_platform_data *pdata = &omap->platdata; + unsigned long flags; + + dev_dbg(dev, "usbhs_runtime_suspend\n"); + + if (!pdata) { + dev_dbg(dev, "missing platform_data\n"); + return -ENODEV; + } + + spin_lock_irqsave(&omap->lock, flags); + + if (is_ehci_tll_mode(pdata->port_mode[0])) { + clk_disable(omap->usbhost_p1_fck); + clk_disable(omap->usbtll_p1_fck); + } + if (is_ehci_tll_mode(pdata->port_mode[1])) { + clk_disable(omap->usbhost_p2_fck); + clk_disable(omap->usbtll_p2_fck); + } + clk_disable(omap->utmi_p2_fck); + clk_disable(omap->utmi_p1_fck); + + if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) + clk_disable(omap->ehci_logic_fck); + + spin_unlock_irqrestore(&omap->lock, flags); + + return 0; +} + +static void omap_usbhs_init(struct device *dev) +{ + struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); + struct usbhs_omap_platform_data *pdata = &omap->platdata; + unsigned long flags; + unsigned reg; + + dev_dbg(dev, "starting TI HSUSB Controller\n"); + + pm_runtime_get_sync(dev); + spin_lock_irqsave(&omap->lock, flags); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { @@ -736,50 +524,6 @@ static int usbhs_enable(struct device *dev) omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); - /* perform TLL soft reset, and wait until reset is complete */ - usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, - OMAP_USBTLL_SYSCONFIG_SOFTRESET); - - /* Wait for TLL reset to complete */ - timeout = jiffies + msecs_to_jiffies(1000); - while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) - & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { - cpu_relax(); - - if (time_after(jiffies, timeout)) { - dev_dbg(dev, "operation timed out\n"); - ret = -EINVAL; - goto err_tll; - } - } - - dev_dbg(dev, "TLL RESET DONE\n"); - - /* (1<<3) = no idle mode only for initial debugging */ - usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, - OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | - OMAP_USBTLL_SYSCONFIG_SIDLEMODE | - OMAP_USBTLL_SYSCONFIG_AUTOIDLE); - - /* Put UHH in NoIdle/NoStandby mode */ - reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG); - if (is_omap_usbhs_rev1(omap)) { - reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP - | OMAP_UHH_SYSCONFIG_SIDLEMODE - | OMAP_UHH_SYSCONFIG_CACTIVITY - | OMAP_UHH_SYSCONFIG_MIDLEMODE); - reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; - - - } else if (is_omap_usbhs_rev2(omap)) { - reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; - reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; - reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; - reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; - } - - usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); - reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN @@ -825,49 +569,6 @@ static int usbhs_enable(struct device *dev) reg &= ~OMAP4_P1_MODE_CLEAR; reg &= ~OMAP4_P2_MODE_CLEAR; - if (is_ehci_phy_mode(pdata->port_mode[0])) { - ret = clk_set_parent(omap->utmi_p1_fck, - omap->xclk60mhsp1_ck); - if (ret != 0) { - dev_err(dev, "xclk60mhsp1_ck set parent" - "failed error:%d\n", ret); - goto err_tll; - } - } else if (is_ehci_tll_mode(pdata->port_mode[0])) { - ret = clk_set_parent(omap->utmi_p1_fck, - omap->init_60m_fclk); - if (ret != 0) { - dev_err(dev, "init_60m_fclk set parent" - "failed error:%d\n", ret); - goto err_tll; - } - clk_enable(omap->usbhost_p1_fck); - clk_enable(omap->usbtll_p1_fck); - } - - if (is_ehci_phy_mode(pdata->port_mode[1])) { - ret = clk_set_parent(omap->utmi_p2_fck, - omap->xclk60mhsp2_ck); - if (ret != 0) { - dev_err(dev, "xclk60mhsp1_ck set parent" - "failed error:%d\n", ret); - goto err_tll; - } - } else if (is_ehci_tll_mode(pdata->port_mode[1])) { - ret = clk_set_parent(omap->utmi_p2_fck, - omap->init_60m_fclk); - if (ret != 0) { - dev_err(dev, "init_60m_fclk set parent" - "failed error:%d\n", ret); - goto err_tll; - } - clk_enable(omap->usbhost_p2_fck); - clk_enable(omap->usbtll_p2_fck); - } - - clk_enable(omap->utmi_p1_fck); - clk_enable(omap->utmi_p2_fck); - if (is_ehci_tll_mode(pdata->port_mode[0]) || (is_ohci_port(pdata->port_mode[0]))) reg |= OMAP4_P1_MODE_TLL; @@ -913,12 +614,15 @@ static int usbhs_enable(struct device *dev) (pdata->ehci_data->reset_gpio_port[1], 1); } -end_count: - omap->count++; spin_unlock_irqrestore(&omap->lock, flags); - return 0; + pm_runtime_put_sync(dev); +} + +static void omap_usbhs_deinit(struct device *dev) +{ + struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); + struct usbhs_omap_platform_data *pdata = &omap->platdata; -err_tll: if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_free(pdata->ehci_data->reset_gpio_port[0]); @@ -926,123 +630,272 @@ err_tll: if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_free(pdata->ehci_data->reset_gpio_port[1]); } - - clk_disable(omap->usbtll_ick); - clk_disable(omap->usbtll_fck); - clk_disable(omap->usbhost_fs_fck); - clk_disable(omap->usbhost_hs_fck); - clk_disable(omap->usbhost_ick); - spin_unlock_irqrestore(&omap->lock, flags); - return ret; } -static void usbhs_disable(struct device *dev) + +/** + * usbhs_omap_probe - initialize TI-based HCDs + * + * Allocates basic resources for this USB host controller. + */ +static int __devinit usbhs_omap_probe(struct platform_device *pdev) { - struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); - struct usbhs_omap_platform_data *pdata = &omap->platdata; - unsigned long flags = 0; - unsigned long timeout; + struct device *dev = &pdev->dev; + struct usbhs_omap_platform_data *pdata = dev->platform_data; + struct usbhs_hcd_omap *omap; + struct resource *res; + int ret = 0; + int i; - dev_dbg(dev, "stopping TI HSUSB Controller\n"); + if (!pdata) { + dev_err(dev, "Missing platform data\n"); + ret = -ENOMEM; + goto end_probe; + } - spin_lock_irqsave(&omap->lock, flags); + omap = kzalloc(sizeof(*omap), GFP_KERNEL); + if (!omap) { + dev_err(dev, "Memory allocation failed\n"); + ret = -ENOMEM; + goto end_probe; + } - if (omap->count == 0) - goto end_disble; + spin_lock_init(&omap->lock); - omap->count--; + for (i = 0; i < OMAP3_HS_USB_PORTS; i++) + omap->platdata.port_mode[i] = pdata->port_mode[i]; + + omap->platdata.ehci_data = pdata->ehci_data; + omap->platdata.ohci_data = pdata->ohci_data; - if (omap->count != 0) - goto end_disble; + pm_runtime_enable(dev); - /* Reset OMAP modules for insmod/rmmod to work */ - usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, - is_omap_usbhs_rev2(omap) ? - OMAP4_UHH_SYSCONFIG_SOFTRESET : - OMAP_UHH_SYSCONFIG_SOFTRESET); - timeout = jiffies + msecs_to_jiffies(100); - while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) - & (1 << 0))) { - cpu_relax(); + for (i = 0; i < OMAP3_HS_USB_PORTS; i++) + if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) || + is_ehci_hsic_mode(i)) { + omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck"); + if (IS_ERR(omap->ehci_logic_fck)) { + ret = PTR_ERR(omap->ehci_logic_fck); + dev_warn(dev, "ehci_logic_fck failed:%d\n", + ret); + } + break; + } - if (time_after(jiffies, timeout)) - dev_dbg(dev, "operation timed out\n"); + omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); + if (IS_ERR(omap->utmi_p1_fck)) { + ret = PTR_ERR(omap->utmi_p1_fck); + dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); + goto err_end; } - while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) - & (1 << 1))) { - cpu_relax(); + omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); + if (IS_ERR(omap->xclk60mhsp1_ck)) { + ret = PTR_ERR(omap->xclk60mhsp1_ck); + dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); + goto err_utmi_p1_fck; + } - if (time_after(jiffies, timeout)) - dev_dbg(dev, "operation timed out\n"); + omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk"); + if (IS_ERR(omap->utmi_p2_fck)) { + ret = PTR_ERR(omap->utmi_p2_fck); + dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); + goto err_xclk60mhsp1_ck; } - while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) - & (1 << 2))) { - cpu_relax(); + omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); + if (IS_ERR(omap->xclk60mhsp2_ck)) { + ret = PTR_ERR(omap->xclk60mhsp2_ck); + dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); + goto err_utmi_p2_fck; + } - if (time_after(jiffies, timeout)) - dev_dbg(dev, "operation timed out\n"); + omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk"); + if (IS_ERR(omap->usbhost_p1_fck)) { + ret = PTR_ERR(omap->usbhost_p1_fck); + dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret); + goto err_xclk60mhsp2_ck; } - usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1)); + omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); + if (IS_ERR(omap->usbtll_p1_fck)) { + ret = PTR_ERR(omap->usbtll_p1_fck); + dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); + goto err_usbhost_p1_fck; + } - while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) - & (1 << 0))) { - cpu_relax(); + omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); + if (IS_ERR(omap->usbhost_p2_fck)) { + ret = PTR_ERR(omap->usbhost_p2_fck); + dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); + goto err_usbtll_p1_fck; + } - if (time_after(jiffies, timeout)) - dev_dbg(dev, "operation timed out\n"); + omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); + if (IS_ERR(omap->usbtll_p2_fck)) { + ret = PTR_ERR(omap->usbtll_p2_fck); + dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); + goto err_usbhost_p2_fck; } - if (is_omap_usbhs_rev2(omap)) { - if (is_ehci_tll_mode(pdata->port_mode[0])) - clk_disable(omap->usbtll_p1_fck); - if (is_ehci_tll_mode(pdata->port_mode[1])) - clk_disable(omap->usbtll_p2_fck); - clk_disable(omap->utmi_p2_fck); - clk_disable(omap->utmi_p1_fck); + omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); + if (IS_ERR(omap->init_60m_fclk)) { + ret = PTR_ERR(omap->init_60m_fclk); + dev_err(dev, "init_60m_fclk failed error:%d\n", ret); + goto err_usbtll_p2_fck; } - clk_disable(omap->usbtll_ick); - clk_disable(omap->usbtll_fck); - clk_disable(omap->usbhost_fs_fck); - clk_disable(omap->usbhost_hs_fck); - clk_disable(omap->usbhost_ick); + if (is_ehci_phy_mode(pdata->port_mode[0])) { + /* for OMAP3 , the clk set paretn fails */ + ret = clk_set_parent(omap->utmi_p1_fck, + omap->xclk60mhsp1_ck); + if (ret != 0) + dev_err(dev, "xclk60mhsp1_ck set parent" + "failed error:%d\n", ret); + } else if (is_ehci_tll_mode(pdata->port_mode[0])) { + ret = clk_set_parent(omap->utmi_p1_fck, + omap->init_60m_fclk); + if (ret != 0) + dev_err(dev, "init_60m_fclk set parent" + "failed error:%d\n", ret); + } - /* The gpio_free migh sleep; so unlock the spinlock */ - spin_unlock_irqrestore(&omap->lock, flags); + if (is_ehci_phy_mode(pdata->port_mode[1])) { + ret = clk_set_parent(omap->utmi_p2_fck, + omap->xclk60mhsp2_ck); + if (ret != 0) + dev_err(dev, "xclk60mhsp2_ck set parent" + "failed error:%d\n", ret); + } else if (is_ehci_tll_mode(pdata->port_mode[1])) { + ret = clk_set_parent(omap->utmi_p2_fck, + omap->init_60m_fclk); + if (ret != 0) + dev_err(dev, "init_60m_fclk set parent" + "failed error:%d\n", ret); + } - if (pdata->ehci_data->phy_reset) { - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) - gpio_free(pdata->ehci_data->reset_gpio_port[0]); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); + if (!res) { + dev_err(dev, "UHH EHCI get resource failed\n"); + ret = -ENODEV; + goto err_init_60m_fclk; + } - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) - gpio_free(pdata->ehci_data->reset_gpio_port[1]); + omap->uhh_base = ioremap(res->start, resource_size(res)); + if (!omap->uhh_base) { + dev_err(dev, "UHH ioremap failed\n"); + ret = -ENOMEM; + goto err_init_60m_fclk; } - return; -end_disble: - spin_unlock_irqrestore(&omap->lock, flags); -} + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); + if (!res) { + dev_err(dev, "UHH EHCI get resource failed\n"); + ret = -ENODEV; + goto err_tll; + } -int omap_usbhs_enable(struct device *dev) -{ - return usbhs_enable(dev->parent); + omap->tll_base = ioremap(res->start, resource_size(res)); + if (!omap->tll_base) { + dev_err(dev, "TLL ioremap failed\n"); + ret = -ENOMEM; + goto err_tll; + } + + platform_set_drvdata(pdev, omap); + + ret = omap_usbhs_alloc_children(pdev); + if (ret) { + dev_err(dev, "omap_usbhs_alloc_children failed\n"); + goto err_alloc; + } + + omap_usbhs_init(dev); + + goto end_probe; + +err_alloc: + iounmap(omap->tll_base); + +err_tll: + iounmap(omap->uhh_base); + +err_init_60m_fclk: + clk_put(omap->init_60m_fclk); + +err_usbtll_p2_fck: + clk_put(omap->usbtll_p2_fck); + +err_usbhost_p2_fck: + clk_put(omap->usbhost_p2_fck); + +err_usbtll_p1_fck: + clk_put(omap->usbtll_p1_fck); + +err_usbhost_p1_fck: + clk_put(omap->usbhost_p1_fck); + +err_xclk60mhsp2_ck: + clk_put(omap->xclk60mhsp2_ck); + +err_utmi_p2_fck: + clk_put(omap->utmi_p2_fck); + +err_xclk60mhsp1_ck: + clk_put(omap->xclk60mhsp1_ck); + +err_utmi_p1_fck: + clk_put(omap->utmi_p1_fck); + +err_end: + clk_put(omap->ehci_logic_fck); + pm_runtime_disable(dev); + kfree(omap); + +end_probe: + return ret; } -EXPORT_SYMBOL_GPL(omap_usbhs_enable); -void omap_usbhs_disable(struct device *dev) +/** + * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs + * @pdev: USB Host Controller being removed + * + * Reverses the effect of usbhs_omap_probe(). + */ +static int __devexit usbhs_omap_remove(struct platform_device *pdev) { - usbhs_disable(dev->parent); + struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); + + omap_usbhs_deinit(&pdev->dev); + iounmap(omap->tll_base); + iounmap(omap->uhh_base); + clk_put(omap->init_60m_fclk); + clk_put(omap->usbtll_p2_fck); + clk_put(omap->usbhost_p2_fck); + clk_put(omap->usbtll_p1_fck); + clk_put(omap->usbhost_p1_fck); + clk_put(omap->xclk60mhsp2_ck); + clk_put(omap->utmi_p2_fck); + clk_put(omap->xclk60mhsp1_ck); + clk_put(omap->utmi_p1_fck); + clk_put(omap->ehci_logic_fck); + pm_runtime_disable(&pdev->dev); + kfree(omap); + + return 0; } -EXPORT_SYMBOL_GPL(omap_usbhs_disable); + +static const struct dev_pm_ops usbhsomap_dev_pm_ops = { + .runtime_suspend = usbhs_runtime_suspend, + .runtime_resume = usbhs_runtime_resume, +}; static struct platform_driver usbhs_omap_driver = { .driver = { .name = (char *)usbhs_driver_name, .owner = THIS_MODULE, + .pm = &usbhsomap_dev_pm_ops, }, .remove = __exit_p(usbhs_omap_remove), }; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index d5fe43d53c51..d1fb561e089d 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1991,6 +1991,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) if (mmc_slot(host).nonremovable) mmc->caps |= MMC_CAP_NONREMOVABLE; + mmc->pm_caps = mmc_slot(host).pm_caps; + omap_hsmmc_conf_bus_power(host); /* Select DMA lines */ @@ -2179,13 +2181,7 @@ static int omap_hsmmc_suspend(struct device *dev) cancel_work_sync(&host->mmc_carddetect_work); ret = mmc_suspend_host(host->mmc); - if (ret == 0) { - omap_hsmmc_disable_irq(host); - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); - if (host->got_dbclk) - clk_disable(host->dbclk); - } else { + if (ret) { host->suspended = 0; if (host->pdata->resume) { ret = host->pdata->resume(&pdev->dev, @@ -2194,9 +2190,20 @@ static int omap_hsmmc_suspend(struct device *dev) dev_dbg(mmc_dev(host->mmc), "Unmask interrupt failed\n"); } + goto err; } - pm_runtime_put_sync(host->dev); + + if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { + omap_hsmmc_disable_irq(host); + OMAP_HSMMC_WRITE(host->base, HCTL, + OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); + } + if (host->got_dbclk) + clk_disable(host->dbclk); + } +err: + pm_runtime_put_sync(host->dev); return ret; } @@ -2216,7 +2223,8 @@ static int omap_hsmmc_resume(struct device *dev) if (host->got_dbclk) clk_enable(host->dbclk); - omap_hsmmc_conf_bus_power(host); + if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) + omap_hsmmc_conf_bus_power(host); if (host->pdata->resume) { ret = host->pdata->resume(&pdev->dev, host->slot_id); diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index cd6d69a6a7d2..08d5f0388877 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/ obj-$(CONFIG_NET_VENDOR_AMD) += amd/ obj-$(CONFIG_NET_VENDOR_APPLE) += apple/ obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/ -obj-$(CONFIG_NET_ATMEL) += cadence/ +obj-$(CONFIG_NET_CADENCE) += cadence/ obj-$(CONFIG_NET_BFIN) += adi/ obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/ obj-$(CONFIG_NET_VENDOR_BROCADE) += brocade/ diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig index b48378a41e49..db931916da08 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -5,8 +5,8 @@ config HAVE_NET_MACB bool -config NET_ATMEL - bool "Atmel devices" +config NET_CADENCE + bool "Cadence devices" default y depends on HAVE_NET_MACB || (ARM && ARCH_AT91RM9200) ---help--- @@ -21,7 +21,7 @@ config NET_ATMEL the remaining Atmel network card questions. If you say Y, you will be asked for your specific card in the following questions. -if NET_ATMEL +if NET_CADENCE config ARM_AT91_ETHER tristate "AT91RM9200 Ethernet support" @@ -33,14 +33,16 @@ config ARM_AT91_ETHER ethernet support, then you should always answer Y to this. config MACB - tristate "Atmel MACB support" + tristate "Cadence MACB/GEM support" depends on HAVE_NET_MACB select PHYLIB ---help--- - The Atmel MACB ethernet interface is found on many AT32 and AT91 - parts. Say Y to include support for the MACB chip. + The Cadence MACB ethernet interface is found on many Atmel AT32 and + AT91 parts. This driver also supports the Cadence GEM (Gigabit + Ethernet MAC found in some ARM SoC devices). Note: the Gigabit mode + is not yet supported. Say Y to include support for the MACB/GEM chip. To compile this driver as a module, choose M here: the module will be called macb. -endif # NET_ATMEL +endif # NET_CADENCE diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c index dfeb46cb3f74..1a5b6efa0120 100644 --- a/drivers/net/ethernet/cadence/at91_ether.c +++ b/drivers/net/ethernet/cadence/at91_ether.c @@ -256,8 +256,7 @@ static void enable_phyirq(struct net_device *dev) unsigned int dsintr, irq_number; int status; - irq_number = lp->board_data.phy_irq_pin; - if (!irq_number) { + if (!gpio_is_valid(lp->board_data.phy_irq_pin)) { /* * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L), * or board does not have it connected. @@ -266,6 +265,7 @@ static void enable_phyirq(struct net_device *dev) return; } + irq_number = lp->board_data.phy_irq_pin; status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); if (status) { printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); @@ -320,8 +320,7 @@ static void disable_phyirq(struct net_device *dev) unsigned int dsintr; unsigned int irq_number; - irq_number = lp->board_data.phy_irq_pin; - if (!irq_number) { + if (!gpio_is_valid(lp->board_data.phy_irq_pin)) { del_timer_sync(&lp->check_timer); return; } @@ -366,6 +365,7 @@ static void disable_phyirq(struct net_device *dev) disable_mdi(); spin_unlock_irq(&lp->lock); + irq_number = lp->board_data.phy_irq_pin; free_irq(irq_number, dev); /* Free interrupt handler */ } @@ -1078,7 +1078,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add netif_carrier_off(dev); /* will be enabled in open() */ /* If board has no PHY IRQ, use a timer to poll the PHY */ - if (!lp->board_data.phy_irq_pin) { + if (!gpio_is_valid(lp->board_data.phy_irq_pin)) { init_timer(&lp->check_timer); lp->check_timer.data = (unsigned long)dev; lp->check_timer.function = at91ether_check_link; @@ -1170,7 +1170,8 @@ static int __devexit at91ether_remove(struct platform_device *pdev) struct net_device *dev = platform_get_drvdata(pdev); struct at91_private *lp = netdev_priv(dev); - if (lp->board_data.phy_irq_pin >= 32) + if (gpio_is_valid(lp->board_data.phy_irq_pin) && + lp->board_data.phy_irq_pin >= 32) gpio_free(lp->board_data.phy_irq_pin); unregister_netdev(dev); @@ -1189,11 +1190,12 @@ static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg) { struct net_device *net_dev = platform_get_drvdata(pdev); struct at91_private *lp = netdev_priv(net_dev); - int phy_irq = lp->board_data.phy_irq_pin; if (netif_running(net_dev)) { - if (phy_irq) + if (gpio_is_valid(lp->board_data.phy_irq_pin)) { + int phy_irq = lp->board_data.phy_irq_pin; disable_irq(phy_irq); + } netif_stop_queue(net_dev); netif_device_detach(net_dev); @@ -1207,7 +1209,6 @@ static int at91ether_resume(struct platform_device *pdev) { struct net_device *net_dev = platform_get_drvdata(pdev); struct at91_private *lp = netdev_priv(net_dev); - int phy_irq = lp->board_data.phy_irq_pin; if (netif_running(net_dev)) { clk_enable(lp->ether_clk); @@ -1215,8 +1216,10 @@ static int at91ether_resume(struct platform_device *pdev) netif_device_attach(net_dev); netif_start_queue(net_dev); - if (phy_irq) + if (gpio_is_valid(lp->board_data.phy_irq_pin)) { + int phy_irq = lp->board_data.phy_irq_pin; enable_irq(phy_irq); + } } return 0; } diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index aa1d597091a8..f3d5c65d99cf 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1,5 +1,5 @@ /* - * Atmel MACB Ethernet Controller driver + * Cadence MACB/GEM Ethernet Controller driver * * Copyright (C) 2004-2006 Atmel Corporation * @@ -23,6 +23,9 @@ #include <linux/platform_data/macb.h> #include <linux/platform_device.h> #include <linux/phy.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_net.h> #include "macb.h" @@ -59,9 +62,9 @@ static void __macb_set_hwaddr(struct macb *bp) u16 top; bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr)); - macb_writel(bp, SA1B, bottom); + macb_or_gem_writel(bp, SA1B, bottom); top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4))); - macb_writel(bp, SA1T, top); + macb_or_gem_writel(bp, SA1T, top); } static void __init macb_get_hwaddr(struct macb *bp) @@ -70,8 +73,8 @@ static void __init macb_get_hwaddr(struct macb *bp) u16 top; u8 addr[6]; - bottom = macb_readl(bp, SA1B); - top = macb_readl(bp, SA1T); + bottom = macb_or_gem_readl(bp, SA1B); + top = macb_or_gem_readl(bp, SA1T); addr[0] = bottom & 0xff; addr[1] = (bottom >> 8) & 0xff; @@ -191,7 +194,6 @@ static int macb_mii_probe(struct net_device *dev) { struct macb *bp = netdev_priv(dev); struct phy_device *phydev; - struct macb_platform_data *pdata; int ret; phydev = phy_find_first(bp->mii_bus); @@ -200,14 +202,11 @@ static int macb_mii_probe(struct net_device *dev) return -1; } - pdata = bp->pdev->dev.platform_data; /* TODO : add pin_irq */ /* attach the mac to the phy */ ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0, - pdata && pdata->is_rmii ? - PHY_INTERFACE_MODE_RMII : - PHY_INTERFACE_MODE_MII); + bp->phy_interface); if (ret) { netdev_err(dev, "Could not attach to PHY\n"); return ret; @@ -285,8 +284,8 @@ err_out: static void macb_update_stats(struct macb *bp) { u32 __iomem *reg = bp->regs + MACB_PFR; - u32 *p = &bp->hw_stats.rx_pause_frames; - u32 *end = &bp->hw_stats.tx_pause_frames + 1; + u32 *p = &bp->hw_stats.macb.rx_pause_frames; + u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1; WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); @@ -580,7 +579,10 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) if (status & MACB_BIT(ISR_ROVR)) { /* We missed at least one packet */ - bp->hw_stats.rx_overruns++; + if (macb_is_gem(bp)) + bp->hw_stats.gem.rx_overruns++; + else + bp->hw_stats.macb.rx_overruns++; } if (status & MACB_BIT(HRESP)) { @@ -790,6 +792,84 @@ static void macb_reset_hw(struct macb *bp) macb_readl(bp, ISR); } +static u32 gem_mdc_clk_div(struct macb *bp) +{ + u32 config; + unsigned long pclk_hz = clk_get_rate(bp->pclk); + + if (pclk_hz <= 20000000) + config = GEM_BF(CLK, GEM_CLK_DIV8); + else if (pclk_hz <= 40000000) + config = GEM_BF(CLK, GEM_CLK_DIV16); + else if (pclk_hz <= 80000000) + config = GEM_BF(CLK, GEM_CLK_DIV32); + else if (pclk_hz <= 120000000) + config = GEM_BF(CLK, GEM_CLK_DIV48); + else if (pclk_hz <= 160000000) + config = GEM_BF(CLK, GEM_CLK_DIV64); + else + config = GEM_BF(CLK, GEM_CLK_DIV96); + + return config; +} + +static u32 macb_mdc_clk_div(struct macb *bp) +{ + u32 config; + unsigned long pclk_hz; + + if (macb_is_gem(bp)) + return gem_mdc_clk_div(bp); + + pclk_hz = clk_get_rate(bp->pclk); + if (pclk_hz <= 20000000) + config = MACB_BF(CLK, MACB_CLK_DIV8); + else if (pclk_hz <= 40000000) + config = MACB_BF(CLK, MACB_CLK_DIV16); + else if (pclk_hz <= 80000000) + config = MACB_BF(CLK, MACB_CLK_DIV32); + else + config = MACB_BF(CLK, MACB_CLK_DIV64); + + return config; +} + +/* + * Get the DMA bus width field of the network configuration register that we + * should program. We find the width from decoding the design configuration + * register to find the maximum supported data bus width. + */ +static u32 macb_dbw(struct macb *bp) +{ + if (!macb_is_gem(bp)) + return 0; + + switch (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1))) { + case 4: + return GEM_BF(DBW, GEM_DBW128); + case 2: + return GEM_BF(DBW, GEM_DBW64); + case 1: + default: + return GEM_BF(DBW, GEM_DBW32); + } +} + +/* + * Configure the receive DMA engine to use the correct receive buffer size. + * This is a configurable parameter for GEM. + */ +static void macb_configure_dma(struct macb *bp) +{ + u32 dmacfg; + + if (macb_is_gem(bp)) { + dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L); + dmacfg |= GEM_BF(RXBS, RX_BUFFER_SIZE / 64); + gem_writel(bp, DMACFG, dmacfg); + } +} + static void macb_init_hw(struct macb *bp) { u32 config; @@ -797,7 +877,7 @@ static void macb_init_hw(struct macb *bp) macb_reset_hw(bp); __macb_set_hwaddr(bp); - config = macb_readl(bp, NCFGR) & MACB_BF(CLK, -1L); + config = macb_mdc_clk_div(bp); config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ config |= MACB_BIT(BIG); /* Receive oversized frames */ @@ -805,8 +885,11 @@ static void macb_init_hw(struct macb *bp) config |= MACB_BIT(CAF); /* Copy All Frames */ if (!(bp->dev->flags & IFF_BROADCAST)) config |= MACB_BIT(NBC); /* No BroadCast */ + config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); + macb_configure_dma(bp); + /* Initialize TX and RX buffers */ macb_writel(bp, RBQP, bp->rx_ring_dma); macb_writel(bp, TBQP, bp->tx_ring_dma); @@ -902,8 +985,8 @@ static void macb_sethashtable(struct net_device *dev) mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); } - macb_writel(bp, HRB, mc_filter[0]); - macb_writel(bp, HRT, mc_filter[1]); + macb_or_gem_writel(bp, HRB, mc_filter[0]); + macb_or_gem_writel(bp, HRT, mc_filter[1]); } /* @@ -925,8 +1008,8 @@ static void macb_set_rx_mode(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */ - macb_writel(bp, HRB, -1); - macb_writel(bp, HRT, -1); + macb_or_gem_writel(bp, HRB, -1); + macb_or_gem_writel(bp, HRT, -1); cfg |= MACB_BIT(NCFGR_MTI); } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */ @@ -934,8 +1017,8 @@ static void macb_set_rx_mode(struct net_device *dev) cfg |= MACB_BIT(NCFGR_MTI); } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */ - macb_writel(bp, HRB, 0); - macb_writel(bp, HRT, 0); + macb_or_gem_writel(bp, HRB, 0); + macb_or_gem_writel(bp, HRT, 0); cfg &= ~MACB_BIT(NCFGR_MTI); } @@ -997,11 +1080,62 @@ static int macb_close(struct net_device *dev) return 0; } +static void gem_update_stats(struct macb *bp) +{ + u32 __iomem *reg = bp->regs + GEM_OTX; + u32 *p = &bp->hw_stats.gem.tx_octets_31_0; + u32 *end = &bp->hw_stats.gem.rx_udp_checksum_errors + 1; + + for (; p < end; p++, reg++) + *p += __raw_readl(reg); +} + +static struct net_device_stats *gem_get_stats(struct macb *bp) +{ + struct gem_stats *hwstat = &bp->hw_stats.gem; + struct net_device_stats *nstat = &bp->stats; + + gem_update_stats(bp); + + nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors + + hwstat->rx_alignment_errors + + hwstat->rx_resource_errors + + hwstat->rx_overruns + + hwstat->rx_oversize_frames + + hwstat->rx_jabbers + + hwstat->rx_undersized_frames + + hwstat->rx_length_field_frame_errors); + nstat->tx_errors = (hwstat->tx_late_collisions + + hwstat->tx_excessive_collisions + + hwstat->tx_underrun + + hwstat->tx_carrier_sense_errors); + nstat->multicast = hwstat->rx_multicast_frames; + nstat->collisions = (hwstat->tx_single_collision_frames + + hwstat->tx_multiple_collision_frames + + hwstat->tx_excessive_collisions); + nstat->rx_length_errors = (hwstat->rx_oversize_frames + + hwstat->rx_jabbers + + hwstat->rx_undersized_frames + + hwstat->rx_length_field_frame_errors); + nstat->rx_over_errors = hwstat->rx_resource_errors; + nstat->rx_crc_errors = hwstat->rx_frame_check_sequence_errors; + nstat->rx_frame_errors = hwstat->rx_alignment_errors; + nstat->rx_fifo_errors = hwstat->rx_overruns; + nstat->tx_aborted_errors = hwstat->tx_excessive_collisions; + nstat->tx_carrier_errors = hwstat->tx_carrier_sense_errors; + nstat->tx_fifo_errors = hwstat->tx_underrun; + + return nstat; +} + static struct net_device_stats *macb_get_stats(struct net_device *dev) { struct macb *bp = netdev_priv(dev); struct net_device_stats *nstat = &bp->stats; - struct macb_stats *hwstat = &bp->hw_stats; + struct macb_stats *hwstat = &bp->hw_stats.macb; + + if (macb_is_gem(bp)) + return gem_get_stats(bp); /* read stats from hardware */ macb_update_stats(bp); @@ -1109,6 +1243,52 @@ static const struct net_device_ops macb_netdev_ops = { #endif }; +#if defined(CONFIG_OF) +static const struct of_device_id macb_dt_ids[] = { + { .compatible = "cdns,at32ap7000-macb" }, + { .compatible = "cdns,at91sam9260-macb" }, + { .compatible = "cdns,macb" }, + { .compatible = "cdns,pc302-gem" }, + { .compatible = "cdns,gem" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, macb_dt_ids); + +static int __devinit macb_get_phy_mode_dt(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + + if (np) + return of_get_phy_mode(np); + + return -ENODEV; +} + +static int __devinit macb_get_hwaddr_dt(struct macb *bp) +{ + struct device_node *np = bp->pdev->dev.of_node; + if (np) { + const char *mac = of_get_mac_address(np); + if (mac) { + memcpy(bp->dev->dev_addr, mac, ETH_ALEN); + return 0; + } + } + + return -ENODEV; +} +#else +static int __devinit macb_get_phy_mode_dt(struct platform_device *pdev) +{ + return -ENODEV; +} +static int __devinit macb_get_hwaddr_dt(struct macb *bp) +{ + return -ENODEV; +} +#endif + static int __init macb_probe(struct platform_device *pdev) { struct macb_platform_data *pdata; @@ -1116,7 +1296,6 @@ static int __init macb_probe(struct platform_device *pdev) struct net_device *dev; struct macb *bp; struct phy_device *phydev; - unsigned long pclk_hz; u32 config; int err = -ENXIO; @@ -1180,31 +1359,37 @@ static int __init macb_probe(struct platform_device *pdev) dev->base_addr = regs->start; /* Set MII management clock divider */ - pclk_hz = clk_get_rate(bp->pclk); - if (pclk_hz <= 20000000) - config = MACB_BF(CLK, MACB_CLK_DIV8); - else if (pclk_hz <= 40000000) - config = MACB_BF(CLK, MACB_CLK_DIV16); - else if (pclk_hz <= 80000000) - config = MACB_BF(CLK, MACB_CLK_DIV32); - else - config = MACB_BF(CLK, MACB_CLK_DIV64); + config = macb_mdc_clk_div(bp); + config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); - macb_get_hwaddr(bp); - pdata = pdev->dev.platform_data; + err = macb_get_hwaddr_dt(bp); + if (err < 0) + macb_get_hwaddr(bp); + + err = macb_get_phy_mode_dt(pdev); + if (err < 0) { + pdata = pdev->dev.platform_data; + if (pdata && pdata->is_rmii) + bp->phy_interface = PHY_INTERFACE_MODE_RMII; + else + bp->phy_interface = PHY_INTERFACE_MODE_MII; + } else { + bp->phy_interface = err; + } - if (pdata && pdata->is_rmii) + if (bp->phy_interface == PHY_INTERFACE_MODE_RMII) #if defined(CONFIG_ARCH_AT91) - macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) ); + macb_or_gem_writel(bp, USRIO, (MACB_BIT(RMII) | + MACB_BIT(CLKEN))); #else - macb_writel(bp, USRIO, 0); + macb_or_gem_writel(bp, USRIO, 0); #endif else #if defined(CONFIG_ARCH_AT91) - macb_writel(bp, USRIO, MACB_BIT(CLKEN)); + macb_or_gem_writel(bp, USRIO, MACB_BIT(CLKEN)); #else - macb_writel(bp, USRIO, MACB_BIT(MII)); + macb_or_gem_writel(bp, USRIO, MACB_BIT(MII)); #endif bp->tx_pending = DEF_TX_RING_PENDING; @@ -1221,8 +1406,9 @@ static int __init macb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - netdev_info(dev, "Atmel MACB at 0x%08lx irq %d (%pM)\n", - dev->base_addr, dev->irq, dev->dev_addr); + netdev_info(dev, "Cadence %s at 0x%08lx irq %d (%pM)\n", + macb_is_gem(bp) ? "GEM" : "MACB", dev->base_addr, + dev->irq, dev->dev_addr); phydev = bp->phy_dev; netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", @@ -1315,6 +1501,7 @@ static struct platform_driver macb_driver = { .driver = { .name = "macb", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(macb_dt_ids), }, }; @@ -1332,6 +1519,6 @@ module_init(macb_init); module_exit(macb_exit); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Atmel MACB Ethernet driver"); +MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver"); MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_ALIAS("platform:macb"); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index d3212f6db703..335e288f5314 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -59,6 +59,24 @@ #define MACB_TPQ 0x00bc #define MACB_USRIO 0x00c0 #define MACB_WOL 0x00c4 +#define MACB_MID 0x00fc + +/* GEM register offsets. */ +#define GEM_NCFGR 0x0004 +#define GEM_USRIO 0x000c +#define GEM_DMACFG 0x0010 +#define GEM_HRB 0x0080 +#define GEM_HRT 0x0084 +#define GEM_SA1B 0x0088 +#define GEM_SA1T 0x008C +#define GEM_OTX 0x0100 +#define GEM_DCFG1 0x0280 +#define GEM_DCFG2 0x0284 +#define GEM_DCFG3 0x0288 +#define GEM_DCFG4 0x028c +#define GEM_DCFG5 0x0290 +#define GEM_DCFG6 0x0294 +#define GEM_DCFG7 0x0298 /* Bitfields in NCR */ #define MACB_LB_OFFSET 0 @@ -126,6 +144,21 @@ #define MACB_IRXFCS_OFFSET 19 #define MACB_IRXFCS_SIZE 1 +/* GEM specific NCFGR bitfields. */ +#define GEM_CLK_OFFSET 18 +#define GEM_CLK_SIZE 3 +#define GEM_DBW_OFFSET 21 +#define GEM_DBW_SIZE 2 + +/* Constants for data bus width. */ +#define GEM_DBW32 0 +#define GEM_DBW64 1 +#define GEM_DBW128 2 + +/* Bitfields in DMACFG. */ +#define GEM_RXBS_OFFSET 16 +#define GEM_RXBS_SIZE 8 + /* Bitfields in NSR */ #define MACB_NSR_LINK_OFFSET 0 #define MACB_NSR_LINK_SIZE 1 @@ -228,12 +261,30 @@ #define MACB_WOL_MTI_OFFSET 19 #define MACB_WOL_MTI_SIZE 1 +/* Bitfields in MID */ +#define MACB_IDNUM_OFFSET 16 +#define MACB_IDNUM_SIZE 16 +#define MACB_REV_OFFSET 0 +#define MACB_REV_SIZE 16 + +/* Bitfields in DCFG1. */ +#define GEM_DBWDEF_OFFSET 25 +#define GEM_DBWDEF_SIZE 3 + /* Constants for CLK */ #define MACB_CLK_DIV8 0 #define MACB_CLK_DIV16 1 #define MACB_CLK_DIV32 2 #define MACB_CLK_DIV64 3 +/* GEM specific constants for CLK. */ +#define GEM_CLK_DIV8 0 +#define GEM_CLK_DIV16 1 +#define GEM_CLK_DIV32 2 +#define GEM_CLK_DIV48 3 +#define GEM_CLK_DIV64 4 +#define GEM_CLK_DIV96 5 + /* Constants for MAN register */ #define MACB_MAN_SOF 1 #define MACB_MAN_WRITE 1 @@ -254,11 +305,52 @@ << MACB_##name##_OFFSET)) \ | MACB_BF(name,value)) +#define GEM_BIT(name) \ + (1 << GEM_##name##_OFFSET) +#define GEM_BF(name, value) \ + (((value) & ((1 << GEM_##name##_SIZE) - 1)) \ + << GEM_##name##_OFFSET) +#define GEM_BFEXT(name, value)\ + (((value) >> GEM_##name##_OFFSET) \ + & ((1 << GEM_##name##_SIZE) - 1)) +#define GEM_BFINS(name, value, old) \ + (((old) & ~(((1 << GEM_##name##_SIZE) - 1) \ + << GEM_##name##_OFFSET)) \ + | GEM_BF(name, value)) + /* Register access macros */ #define macb_readl(port,reg) \ __raw_readl((port)->regs + MACB_##reg) #define macb_writel(port,reg,value) \ __raw_writel((value), (port)->regs + MACB_##reg) +#define gem_readl(port, reg) \ + __raw_readl((port)->regs + GEM_##reg) +#define gem_writel(port, reg, value) \ + __raw_writel((value), (port)->regs + GEM_##reg) + +/* + * Conditional GEM/MACB macros. These perform the operation to the correct + * register dependent on whether the device is a GEM or a MACB. For registers + * and bitfields that are common across both devices, use macb_{read,write}l + * to avoid the cost of the conditional. + */ +#define macb_or_gem_writel(__bp, __reg, __value) \ + ({ \ + if (macb_is_gem((__bp))) \ + gem_writel((__bp), __reg, __value); \ + else \ + macb_writel((__bp), __reg, __value); \ + }) + +#define macb_or_gem_readl(__bp, __reg) \ + ({ \ + u32 __v; \ + if (macb_is_gem((__bp))) \ + __v = gem_readl((__bp), __reg); \ + else \ + __v = macb_readl((__bp), __reg); \ + __v; \ + }) struct dma_desc { u32 addr; @@ -358,6 +450,54 @@ struct macb_stats { u32 tx_pause_frames; }; +struct gem_stats { + u32 tx_octets_31_0; + u32 tx_octets_47_32; + u32 tx_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 tx_pause_frames; + u32 tx_64_byte_frames; + u32 tx_65_127_byte_frames; + u32 tx_128_255_byte_frames; + u32 tx_256_511_byte_frames; + u32 tx_512_1023_byte_frames; + u32 tx_1024_1518_byte_frames; + u32 tx_greater_than_1518_byte_frames; + u32 tx_underrun; + u32 tx_single_collision_frames; + u32 tx_multiple_collision_frames; + u32 tx_excessive_collisions; + u32 tx_late_collisions; + u32 tx_deferred_frames; + u32 tx_carrier_sense_errors; + u32 rx_octets_31_0; + u32 rx_octets_47_32; + u32 rx_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 rx_pause_frames; + u32 rx_64_byte_frames; + u32 rx_65_127_byte_frames; + u32 rx_128_255_byte_frames; + u32 rx_256_511_byte_frames; + u32 rx_512_1023_byte_frames; + u32 rx_1024_1518_byte_frames; + u32 rx_greater_than_1518_byte_frames; + u32 rx_undersized_frames; + u32 rx_oversize_frames; + u32 rx_jabbers; + u32 rx_frame_check_sequence_errors; + u32 rx_length_field_frame_errors; + u32 rx_symbol_errors; + u32 rx_alignment_errors; + u32 rx_resource_errors; + u32 rx_overruns; + u32 rx_ip_header_checksum_errors; + u32 rx_tcp_checksum_errors; + u32 rx_udp_checksum_errors; +}; + struct macb { void __iomem *regs; @@ -376,7 +516,10 @@ struct macb { struct net_device *dev; struct napi_struct napi; struct net_device_stats stats; - struct macb_stats hw_stats; + union { + struct macb_stats macb; + struct gem_stats gem; + } hw_stats; dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; @@ -389,6 +532,13 @@ struct macb { unsigned int link; unsigned int speed; unsigned int duplex; + + phy_interface_t phy_interface; }; +static inline bool macb_is_gem(struct macb *bp) +{ + return MACB_BFEXT(IDNUM, macb_readl(bp, MID)) == 0x2; +} + #endif /* _MACB_H */ diff --git a/drivers/pcmcia/pxa2xx_cm_x255.c b/drivers/pcmcia/pxa2xx_cm_x255.c index 0b4f946cf13a..31ab6ddf52c9 100644 --- a/drivers/pcmcia/pxa2xx_cm_x255.c +++ b/drivers/pcmcia/pxa2xx_cm_x255.c @@ -16,8 +16,6 @@ #include <linux/gpio.h> #include <linux/export.h> -#include <asm/mach-types.h> - #include "soc_common.h" #define GPIO_PCMCIA_SKTSEL (54) @@ -27,15 +25,15 @@ #define GPIO_PCMCIA_S1_RDYINT (8) #define GPIO_PCMCIA_RESET (9) -#define PCMCIA_S0_CD_VALID IRQ_GPIO(GPIO_PCMCIA_S0_CD_VALID) -#define PCMCIA_S1_CD_VALID IRQ_GPIO(GPIO_PCMCIA_S1_CD_VALID) -#define PCMCIA_S0_RDYINT IRQ_GPIO(GPIO_PCMCIA_S0_RDYINT) -#define PCMCIA_S1_RDYINT IRQ_GPIO(GPIO_PCMCIA_S1_RDYINT) +#define PCMCIA_S0_CD_VALID gpio_to_irq(GPIO_PCMCIA_S0_CD_VALID) +#define PCMCIA_S1_CD_VALID gpio_to_irq(GPIO_PCMCIA_S1_CD_VALID) +#define PCMCIA_S0_RDYINT gpio_to_irq(GPIO_PCMCIA_S0_RDYINT) +#define PCMCIA_S1_RDYINT gpio_to_irq(GPIO_PCMCIA_S1_RDYINT) static struct pcmcia_irqs irqs[] = { - { 0, PCMCIA_S0_CD_VALID, "PCMCIA0 CD" }, - { 1, PCMCIA_S1_CD_VALID, "PCMCIA1 CD" }, + { .sock = 0, .str = "PCMCIA0 CD" }, + { .sock = 1, .str = "PCMCIA1 CD" }, }; static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt) @@ -46,6 +44,8 @@ static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt) gpio_direction_output(GPIO_PCMCIA_RESET, 0); skt->socket.pci_irq = skt->nr == 0 ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT; + irqs[0].irq = PCMCIA_S0_CD_VALID; + irqs[1].irq = PCMCIA_S1_CD_VALID; ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); if (!ret) gpio_free(GPIO_PCMCIA_RESET); diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c index 923f315926ef..3dc7621a0767 100644 --- a/drivers/pcmcia/pxa2xx_cm_x270.c +++ b/drivers/pcmcia/pxa2xx_cm_x270.c @@ -16,20 +16,18 @@ #include <linux/gpio.h> #include <linux/export.h> -#include <asm/mach-types.h> - #include "soc_common.h" #define GPIO_PCMCIA_S0_CD_VALID (84) #define GPIO_PCMCIA_S0_RDYINT (82) #define GPIO_PCMCIA_RESET (53) -#define PCMCIA_S0_CD_VALID IRQ_GPIO(GPIO_PCMCIA_S0_CD_VALID) -#define PCMCIA_S0_RDYINT IRQ_GPIO(GPIO_PCMCIA_S0_RDYINT) +#define PCMCIA_S0_CD_VALID gpio_to_irq(GPIO_PCMCIA_S0_CD_VALID) +#define PCMCIA_S0_RDYINT gpio_to_irq(GPIO_PCMCIA_S0_RDYINT) static struct pcmcia_irqs irqs[] = { - { 0, PCMCIA_S0_CD_VALID, "PCMCIA0 CD" }, + { .sock = 0, .str = "PCMCIA0 CD" }, }; static int cmx270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) @@ -40,6 +38,7 @@ static int cmx270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) gpio_direction_output(GPIO_PCMCIA_RESET, 0); skt->socket.pci_irq = PCMCIA_S0_RDYINT; + irqs[0].irq = PCMCIA_S0_CD_VALID; ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); if (!ret) gpio_free(GPIO_PCMCIA_RESET); diff --git a/drivers/pcmcia/pxa2xx_e740.c b/drivers/pcmcia/pxa2xx_e740.c index 8bfbd4dca131..17cd2ce7428f 100644 --- a/drivers/pcmcia/pxa2xx_e740.c +++ b/drivers/pcmcia/pxa2xx_e740.c @@ -26,20 +26,23 @@ static struct pcmcia_irqs cd_irqs[] = { { .sock = 0, - .irq = IRQ_GPIO(GPIO_E740_PCMCIA_CD0), .str = "CF card detect" }, { .sock = 1, - .irq = IRQ_GPIO(GPIO_E740_PCMCIA_CD1), .str = "Wifi switch" }, }; static int e740_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - skt->socket.pci_irq = skt->nr == 0 ? IRQ_GPIO(GPIO_E740_PCMCIA_RDY0) : - IRQ_GPIO(GPIO_E740_PCMCIA_RDY1); + if (skt->nr == 0) + skt->socket.pci_irq = gpio_to_irq(GPIO_E740_PCMCIA_RDY0); + else + skt->socket.pci_irq = gpio_to_irq(GPIO_E740_PCMCIA_RDY1); + + cd_irqs[0].irq = gpio_to_irq(GPIO_E740_PCMCIA_CD0); + cd_irqs[1].irq = gpio_to_irq(GPIO_E740_PCMCIA_CD1); return soc_pcmcia_request_irqs(skt, &cd_irqs[skt->nr], 1); } diff --git a/drivers/pcmcia/pxa2xx_palmld.c b/drivers/pcmcia/pxa2xx_palmld.c index d589ad1dcd4c..6a8e011a8c13 100644 --- a/drivers/pcmcia/pxa2xx_palmld.c +++ b/drivers/pcmcia/pxa2xx_palmld.c @@ -33,7 +33,7 @@ static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt) ret = gpio_request_array(palmld_pcmcia_gpios, ARRAY_SIZE(palmld_pcmcia_gpios)); - skt->socket.pci_irq = IRQ_GPIO(GPIO_NR_PALMLD_PCMCIA_READY); + skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMLD_PCMCIA_READY); return ret; } diff --git a/drivers/pcmcia/pxa2xx_palmtc.c b/drivers/pcmcia/pxa2xx_palmtc.c index 9c6a04b2f71b..9e38de769ba3 100644 --- a/drivers/pcmcia/pxa2xx_palmtc.c +++ b/drivers/pcmcia/pxa2xx_palmtc.c @@ -37,7 +37,7 @@ static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) ret = gpio_request_array(palmtc_pcmcia_gpios, ARRAY_SIZE(palmtc_pcmcia_gpios)); - skt->socket.pci_irq = IRQ_GPIO(GPIO_NR_PALMTC_PCMCIA_READY); + skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMTC_PCMCIA_READY); return ret; } diff --git a/drivers/pcmcia/pxa2xx_stargate2.c b/drivers/pcmcia/pxa2xx_stargate2.c index 939622251dfb..6c2366b74a35 100644 --- a/drivers/pcmcia/pxa2xx_stargate2.c +++ b/drivers/pcmcia/pxa2xx_stargate2.c @@ -34,7 +34,7 @@ #define SG2_S0_GPIO_READY 81 static struct pcmcia_irqs irqs[] = { - { 0, IRQ_GPIO(SG2_S0_GPIO_DETECT), "PCMCIA0 CD" }, + {.sock = 0, .str = "PCMCIA0 CD" }, }; static struct gpio sg2_pcmcia_gpios[] = { @@ -44,7 +44,9 @@ static struct gpio sg2_pcmcia_gpios[] = { static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - skt->socket.pci_irq = IRQ_GPIO(SG2_S0_GPIO_READY); + skt->socket.pci_irq = gpio_to_irq(SG2_S0_GPIO_READY); + irqs[0].irq = gpio_to_irq(SG2_S0_GPIO_DETECT); + return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c index 57ddb969d888..7c33f898135a 100644 --- a/drivers/pcmcia/pxa2xx_trizeps4.c +++ b/drivers/pcmcia/pxa2xx_trizeps4.c @@ -30,7 +30,7 @@ extern void board_pcmcia_power(int power); static struct pcmcia_irqs irqs[] = { - { 0, IRQ_GPIO(GPIO_PCD), "cs0_cd" } + { .sock = 0, .str = "cs0_cd" } /* on other baseboards we can have more inputs */ }; @@ -53,7 +53,8 @@ static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) gpio_free(GPIO_PRDY); return -EINVAL; } - skt->socket.pci_irq = IRQ_GPIO(GPIO_PRDY); + skt->socket.pci_irq = gpio_to_irq(GPIO_PRDY); + irqs[0].irq = gpio_to_irq(GPIO_PCD); break; default: break; diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c index 66ab92cf3105..61b17d235dbe 100644 --- a/drivers/pcmcia/pxa2xx_vpac270.c +++ b/drivers/pcmcia/pxa2xx_vpac270.c @@ -38,12 +38,10 @@ static struct gpio vpac270_cf_gpios[] = { static struct pcmcia_irqs cd_irqs[] = { { .sock = 0, - .irq = IRQ_GPIO(GPIO84_VPAC270_PCMCIA_CD), .str = "PCMCIA CD" }, { .sock = 1, - .irq = IRQ_GPIO(GPIO17_VPAC270_CF_CD), .str = "CF CD" }, }; @@ -57,6 +55,7 @@ static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) ARRAY_SIZE(vpac270_pcmcia_gpios)); skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY); + cd_irqs[0].irq = gpio_to_irq(GPIO84_VPAC270_PCMCIA_CD); if (!ret) ret = soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1); @@ -65,6 +64,7 @@ static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) ARRAY_SIZE(vpac270_cf_gpios)); skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY); + cd_irqs[1].irq = gpio_to_irq(GPIO17_VPAC270_CF_CD); if (!ret) ret = soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 53eb4e55b289..877cf6fdcf24 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -774,7 +774,7 @@ config RTC_DRV_EP93XX config RTC_DRV_SA1100 tristate "SA11x0/PXA2xx" - depends on ARCH_SA1100 || ARCH_PXA + depends on ARCH_SA1100 || ARCH_PXA || ARCH_MMP help If you say Y here you will get access to the real time clock built into your SA11x0 or PXA2xx CPU. diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 0b40bb88a884..fc1ffe97fca1 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -27,35 +27,42 @@ #include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h> -#include <linux/string.h> #include <linux/pm.h> -#include <linux/bitops.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/io.h> #include <mach/hardware.h> #include <asm/irq.h> -#ifdef CONFIG_ARCH_PXA -#include <mach/regs-rtc.h> -#include <mach/regs-ost.h> -#endif - #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 - -static const unsigned long RTC_FREQ = 1024; -static struct rtc_time rtc_alarm; -static DEFINE_SPINLOCK(sa1100_rtc_lock); - -static inline int rtc_periodic_alarm(struct rtc_time *tm) -{ - return (tm->tm_year == -1) || - ((unsigned)tm->tm_mon >= 12) || - ((unsigned)(tm->tm_mday - 1) >= 31) || - ((unsigned)tm->tm_hour > 23) || - ((unsigned)tm->tm_min > 59) || - ((unsigned)tm->tm_sec > 59); -} - +#define RTC_FREQ 1024 + +#define RCNR 0x00 /* RTC Count Register */ +#define RTAR 0x04 /* RTC Alarm Register */ +#define RTSR 0x08 /* RTC Status Register */ +#define RTTR 0x0c /* RTC Timer Trim Register */ + +#define RTSR_HZE (1 << 3) /* HZ interrupt enable */ +#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */ +#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */ +#define RTSR_AL (1 << 0) /* RTC alarm detected */ + +#define rtc_readl(sa1100_rtc, reg) \ + readl_relaxed((sa1100_rtc)->base + (reg)) +#define rtc_writel(sa1100_rtc, reg, value) \ + writel_relaxed((value), (sa1100_rtc)->base + (reg)) + +struct sa1100_rtc { + struct resource *ress; + void __iomem *base; + struct clk *clk; + int irq_1Hz; + int irq_Alrm; + struct rtc_device *rtc; + spinlock_t lock; /* Protects this structure */ +}; /* * Calculate the next alarm time given the requested alarm time mask * and the current time. @@ -83,46 +90,26 @@ static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, } } -static int rtc_update_alarm(struct rtc_time *alrm) -{ - struct rtc_time alarm_tm, now_tm; - unsigned long now, time; - int ret; - - do { - now = RCNR; - rtc_time_to_tm(now, &now_tm); - rtc_next_alarm_time(&alarm_tm, &now_tm, alrm); - ret = rtc_tm_to_time(&alarm_tm, &time); - if (ret != 0) - break; - - RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); - RTAR = time; - } while (now != RCNR); - - return ret; -} - static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) { struct platform_device *pdev = to_platform_device(dev_id); - struct rtc_device *rtc = platform_get_drvdata(pdev); + struct sa1100_rtc *sa1100_rtc = platform_get_drvdata(pdev); unsigned int rtsr; unsigned long events = 0; - spin_lock(&sa1100_rtc_lock); + spin_lock(&sa1100_rtc->lock); - rtsr = RTSR; /* clear interrupt sources */ - RTSR = 0; + rtsr = rtc_readl(sa1100_rtc, RTSR); + rtc_writel(sa1100_rtc, RTSR, 0); + /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_probe(). */ if (rtsr & (RTSR_ALE | RTSR_HZE)) { /* This is the original code, before there was the if test * above. This code does not clear interrupts that were not * enabled. */ - RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); + rtc_writel(sa1100_rtc, RTSR, (RTSR_AL | RTSR_HZ) & (rtsr >> 2)); } else { /* For some reason, it is possible to enter this routine * without interruptions enabled, it has been tested with @@ -131,13 +118,13 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) * This situation leads to an infinite "loop" of interrupt * routine calling and as a result the processor seems to * lock on its first call to open(). */ - RTSR = RTSR_AL | RTSR_HZ; + rtc_writel(sa1100_rtc, RTSR, (RTSR_AL | RTSR_HZ)); } /* clear alarm interrupt if it has occurred */ if (rtsr & RTSR_AL) rtsr &= ~RTSR_ALE; - RTSR = rtsr & (RTSR_ALE | RTSR_HZE); + rtc_writel(sa1100_rtc, RTSR, rtsr & (RTSR_ALE | RTSR_HZE)); /* update irq data & counter */ if (rtsr & RTSR_AL) @@ -145,91 +132,100 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) if (rtsr & RTSR_HZ) events |= RTC_UF | RTC_IRQF; - rtc_update_irq(rtc, 1, events); + rtc_update_irq(sa1100_rtc->rtc, 1, events); - if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm)) - rtc_update_alarm(&rtc_alarm); - - spin_unlock(&sa1100_rtc_lock); + spin_unlock(&sa1100_rtc->lock); return IRQ_HANDLED; } static int sa1100_rtc_open(struct device *dev) { + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); int ret; - struct platform_device *plat_dev = to_platform_device(dev); - struct rtc_device *rtc = platform_get_drvdata(plat_dev); - ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, - "rtc 1Hz", dev); + ret = request_irq(sa1100_rtc->irq_1Hz, sa1100_rtc_interrupt, + IRQF_DISABLED, "rtc 1Hz", dev); if (ret) { - dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); + dev_err(dev, "IRQ %d already in use.\n", sa1100_rtc->irq_1Hz); goto fail_ui; } - ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, - "rtc Alrm", dev); + ret = request_irq(sa1100_rtc->irq_Alrm, sa1100_rtc_interrupt, + IRQF_DISABLED, "rtc Alrm", dev); if (ret) { - dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); + dev_err(dev, "IRQ %d already in use.\n", sa1100_rtc->irq_Alrm); goto fail_ai; } - rtc->max_user_freq = RTC_FREQ; - rtc_irq_set_freq(rtc, NULL, RTC_FREQ); + sa1100_rtc->rtc->max_user_freq = RTC_FREQ; + rtc_irq_set_freq(sa1100_rtc->rtc, NULL, RTC_FREQ); return 0; fail_ai: - free_irq(IRQ_RTC1Hz, dev); + free_irq(sa1100_rtc->irq_1Hz, dev); fail_ui: return ret; } static void sa1100_rtc_release(struct device *dev) { - spin_lock_irq(&sa1100_rtc_lock); - RTSR = 0; - OIER &= ~OIER_E1; - OSSR = OSSR_M1; - spin_unlock_irq(&sa1100_rtc_lock); - - free_irq(IRQ_RTCAlrm, dev); - free_irq(IRQ_RTC1Hz, dev); + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); + + spin_lock_irq(&sa1100_rtc->lock); + rtc_writel(sa1100_rtc, RTSR, 0); + spin_unlock_irq(&sa1100_rtc->lock); + + free_irq(sa1100_rtc->irq_Alrm, dev); + free_irq(sa1100_rtc->irq_1Hz, dev); } static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - spin_lock_irq(&sa1100_rtc_lock); + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); + unsigned int rtsr; + + spin_lock_irq(&sa1100_rtc->lock); + + rtsr = rtc_readl(sa1100_rtc, RTSR); if (enabled) - RTSR |= RTSR_ALE; + rtsr |= RTSR_ALE; else - RTSR &= ~RTSR_ALE; - spin_unlock_irq(&sa1100_rtc_lock); + rtsr &= ~RTSR_ALE; + rtc_writel(sa1100_rtc, RTSR, rtsr); + + spin_unlock_irq(&sa1100_rtc->lock); return 0; } static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) { - rtc_time_to_tm(RCNR, tm); + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); + + rtc_time_to_tm(rtc_readl(sa1100_rtc, RCNR), tm); return 0; } static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) { + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); unsigned long time; int ret; ret = rtc_tm_to_time(tm, &time); if (ret == 0) - RCNR = time; + rtc_writel(sa1100_rtc, RCNR, time); return ret; } static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - u32 rtsr; + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); + unsigned long time; + unsigned int rtsr; - memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time)); - rtsr = RTSR; + time = rtc_readl(sa1100_rtc, RCNR); + rtc_time_to_tm(time, &alrm->time); + rtsr = rtc_readl(sa1100_rtc, RTSR); alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; return 0; @@ -237,26 +233,39 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - int ret; + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); + struct rtc_time now_tm, alarm_tm; + unsigned long time, alarm; + unsigned int rtsr; - spin_lock_irq(&sa1100_rtc_lock); - ret = rtc_update_alarm(&alrm->time); - if (ret == 0) { - if (alrm->enabled) - RTSR |= RTSR_ALE; - else - RTSR &= ~RTSR_ALE; - } - spin_unlock_irq(&sa1100_rtc_lock); + spin_lock_irq(&sa1100_rtc->lock); - return ret; + time = rtc_readl(sa1100_rtc, RCNR); + rtc_time_to_tm(time, &now_tm); + rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time); + rtc_tm_to_time(&alarm_tm, &alarm); + rtc_writel(sa1100_rtc, RTAR, alarm); + + rtsr = rtc_readl(sa1100_rtc, RTSR); + if (alrm->enabled) + rtsr |= RTSR_ALE; + else + rtsr &= ~RTSR_ALE; + rtc_writel(sa1100_rtc, RTSR, rtsr); + + spin_unlock_irq(&sa1100_rtc->lock); + + return 0; } static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) { - seq_printf(seq, "trim/divider\t\t: 0x%08x\n", (u32) RTTR); - seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", (u32)RTSR); + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); + seq_printf(seq, "trim/divider\t\t: 0x%08x\n", + rtc_readl(sa1100_rtc, RTTR)); + seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", + rtc_readl(sa1100_rtc, RTSR)); return 0; } @@ -273,7 +282,51 @@ static const struct rtc_class_ops sa1100_rtc_ops = { static int sa1100_rtc_probe(struct platform_device *pdev) { - struct rtc_device *rtc; + struct sa1100_rtc *sa1100_rtc; + unsigned int rttr; + int ret; + + sa1100_rtc = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL); + if (!sa1100_rtc) + return -ENOMEM; + + spin_lock_init(&sa1100_rtc->lock); + platform_set_drvdata(pdev, sa1100_rtc); + + ret = -ENXIO; + sa1100_rtc->ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!sa1100_rtc->ress) { + dev_err(&pdev->dev, "No I/O memory resource defined\n"); + goto err_ress; + } + + sa1100_rtc->irq_1Hz = platform_get_irq(pdev, 0); + if (sa1100_rtc->irq_1Hz < 0) { + dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n"); + goto err_ress; + } + sa1100_rtc->irq_Alrm = platform_get_irq(pdev, 1); + if (sa1100_rtc->irq_Alrm < 0) { + dev_err(&pdev->dev, "No alarm IRQ resource defined\n"); + goto err_ress; + } + + ret = -ENOMEM; + sa1100_rtc->base = ioremap(sa1100_rtc->ress->start, + resource_size(sa1100_rtc->ress)); + if (!sa1100_rtc->base) { + dev_err(&pdev->dev, "Unable to map pxa RTC I/O memory\n"); + goto err_map; + } + + sa1100_rtc->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(sa1100_rtc->clk)) { + dev_err(&pdev->dev, "failed to find rtc clock source\n"); + ret = PTR_ERR(sa1100_rtc->clk); + goto err_clk; + } + clk_prepare(sa1100_rtc->clk); + clk_enable(sa1100_rtc->clk); /* * According to the manual we should be able to let RTTR be zero @@ -282,24 +335,24 @@ static int sa1100_rtc_probe(struct platform_device *pdev) * If the clock divider is uninitialized then reset it to the * default value to get the 1Hz clock. */ - if (RTTR == 0) { - RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - dev_warn(&pdev->dev, "warning: " - "initializing default clock divider/trim value\n"); + if (rtc_readl(sa1100_rtc, RTTR) == 0) { + rttr = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); + rtc_writel(sa1100_rtc, RTTR, rttr); + dev_warn(&pdev->dev, "warning: initializing default clock" + " divider/trim value\n"); /* The current RTC value probably doesn't make sense either */ - RCNR = 0; + rtc_writel(sa1100_rtc, RCNR, 0); } device_init_wakeup(&pdev->dev, 1); - rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, - THIS_MODULE); - - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - platform_set_drvdata(pdev, rtc); - + sa1100_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &sa1100_rtc_ops, THIS_MODULE); + if (IS_ERR(sa1100_rtc->rtc)) { + dev_err(&pdev->dev, "Failed to register RTC device -> %d\n", + ret); + goto err_rtc_reg; + } /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_interrupt(). * @@ -322,33 +375,46 @@ static int sa1100_rtc_probe(struct platform_device *pdev) * * Notice that clearing bit 1 and 0 is accomplished by writting ONES to * the corresponding bits in RTSR. */ - RTSR = RTSR_AL | RTSR_HZ; + rtc_writel(sa1100_rtc, RTSR, (RTSR_AL | RTSR_HZ)); return 0; + +err_rtc_reg: +err_clk: + iounmap(sa1100_rtc->base); +err_ress: +err_map: + kfree(sa1100_rtc); + return ret; } static int sa1100_rtc_remove(struct platform_device *pdev) { - struct rtc_device *rtc = platform_get_drvdata(pdev); - - if (rtc) - rtc_device_unregister(rtc); + struct sa1100_rtc *sa1100_rtc = platform_get_drvdata(pdev); + rtc_device_unregister(sa1100_rtc->rtc); + clk_disable(sa1100_rtc->clk); + clk_unprepare(sa1100_rtc->clk); + iounmap(sa1100_rtc->base); return 0; } #ifdef CONFIG_PM static int sa1100_rtc_suspend(struct device *dev) { + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); + if (device_may_wakeup(dev)) - enable_irq_wake(IRQ_RTCAlrm); + enable_irq_wake(sa1100_rtc->irq_Alrm); return 0; } static int sa1100_rtc_resume(struct device *dev) { + struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); + if (device_may_wakeup(dev)) - disable_irq_wake(IRQ_RTCAlrm); + disable_irq_wake(sa1100_rtc->irq_Alrm); return 0; } diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 791f11bed606..75823a1abeb6 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -48,6 +48,7 @@ config USB_ARCH_HAS_OHCI default y if ARCH_DAVINCI_DA8XX default y if ARCH_CNS3XXX default y if PLAT_SPEAR + default y if ARCH_EXYNOS # PPC: default y if STB03xxx default y if PPC_MPC52xx diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index a52769b5c904..4c0c9734251d 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -380,6 +380,12 @@ config USB_OHCI_SH Enables support for the on-chip OHCI controller on the SuperH. If you use the PCI OHCI controller, this option is not necessary. +config USB_OHCI_EXYNOS + boolean "OHCI support for Samsung EXYNOS SoC Series" + depends on USB_OHCI_HCD && ARCH_EXYNOS + help + Enable support for the Samsung Exynos SOC's on-chip OHCI controller. + config USB_CNS3XXX_OHCI bool "Cavium CNS3XXX OHCI Module" depends on USB_OHCI_HCD && ARCH_CNS3XXX diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index e33baf9052cb..bba9850f32f0 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -41,6 +41,7 @@ #include <linux/usb/ulpi.h> #include <plat/usb.h> #include <linux/regulator/consumer.h> +#include <linux/pm_runtime.h> /* EHCI Register Set */ #define EHCI_INSNREG04 (0xA0) @@ -190,11 +191,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) } } - ret = omap_usbhs_enable(dev); - if (ret) { - dev_err(dev, "failed to start usbhs with err %d\n", ret); - goto err_enable; - } + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); /* * An undocumented "feature" in the OMAP3 EHCI controller, @@ -242,11 +240,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) return 0; err_add_hcd: - omap_usbhs_disable(dev); - -err_enable: disable_put_regulator(pdata); - usb_put_hcd(hcd); + pm_runtime_put_sync(dev); err_io: iounmap(regs); @@ -268,10 +263,12 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev) struct usb_hcd *hcd = dev_get_drvdata(dev); usb_remove_hcd(hcd); - omap_usbhs_disable(dev); disable_put_regulator(dev->platform_data); iounmap(hcd->regs); usb_put_hcd(hcd); + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + return 0; } diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c new file mode 100644 index 000000000000..55aa35aa3d7b --- /dev/null +++ b/drivers/usb/host/ohci-exynos.c @@ -0,0 +1,274 @@ +/* + * SAMSUNG EXYNOS USB HOST OHCI Controller + * + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * Author: Jingoo Han <jg1.han@samsung.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <mach/ohci.h> +#include <plat/usb-phy.h> + +struct exynos_ohci_hcd { + struct device *dev; + struct usb_hcd *hcd; + struct clk *clk; +}; + +static int ohci_exynos_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci); + + ret = ohci_init(ohci); + if (ret < 0) + return ret; + + ret = ohci_run(ohci); + if (ret < 0) { + err("can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static const struct hc_driver exynos_ohci_hc_driver = { + .description = hcd_name, + .product_desc = "EXYNOS OHCI Host Controller", + .hcd_priv_size = sizeof(struct ohci_hcd), + + .irq = ohci_irq, + .flags = HCD_MEMORY|HCD_USB11, + + .start = ohci_exynos_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + .get_frame_number = ohci_get_frame, + + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +static int __devinit exynos_ohci_probe(struct platform_device *pdev) +{ + struct exynos4_ohci_platdata *pdata; + struct exynos_ohci_hcd *exynos_ohci; + struct usb_hcd *hcd; + struct ohci_hcd *ohci; + struct resource *res; + int irq; + int err; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "No platform data defined\n"); + return -EINVAL; + } + + exynos_ohci = kzalloc(sizeof(struct exynos_ohci_hcd), GFP_KERNEL); + if (!exynos_ohci) + return -ENOMEM; + + exynos_ohci->dev = &pdev->dev; + + hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, + dev_name(&pdev->dev)); + if (!hcd) { + dev_err(&pdev->dev, "Unable to create HCD\n"); + err = -ENOMEM; + goto fail_hcd; + } + + exynos_ohci->hcd = hcd; + exynos_ohci->clk = clk_get(&pdev->dev, "usbhost"); + + if (IS_ERR(exynos_ohci->clk)) { + dev_err(&pdev->dev, "Failed to get usbhost clock\n"); + err = PTR_ERR(exynos_ohci->clk); + goto fail_clk; + } + + err = clk_enable(exynos_ohci->clk); + if (err) + goto fail_clken; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Failed to get I/O memory\n"); + err = -ENXIO; + goto fail_io; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + hcd->regs = ioremap(res->start, resource_size(res)); + if (!hcd->regs) { + dev_err(&pdev->dev, "Failed to remap I/O memory\n"); + err = -ENOMEM; + goto fail_io; + } + + irq = platform_get_irq(pdev, 0); + if (!irq) { + dev_err(&pdev->dev, "Failed to get IRQ\n"); + err = -ENODEV; + goto fail; + } + + if (pdata->phy_init) + pdata->phy_init(pdev, S5P_USB_PHY_HOST); + + ohci = hcd_to_ohci(hcd); + ohci_hcd_init(ohci); + + err = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (err) { + dev_err(&pdev->dev, "Failed to add USB HCD\n"); + goto fail; + } + + platform_set_drvdata(pdev, exynos_ohci); + + return 0; + +fail: + iounmap(hcd->regs); +fail_io: + clk_disable(exynos_ohci->clk); +fail_clken: + clk_put(exynos_ohci->clk); +fail_clk: + usb_put_hcd(hcd); +fail_hcd: + kfree(exynos_ohci); + return err; +} + +static int __devexit exynos_ohci_remove(struct platform_device *pdev) +{ + struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; + struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); + struct usb_hcd *hcd = exynos_ohci->hcd; + + usb_remove_hcd(hcd); + + if (pdata && pdata->phy_exit) + pdata->phy_exit(pdev, S5P_USB_PHY_HOST); + + iounmap(hcd->regs); + + clk_disable(exynos_ohci->clk); + clk_put(exynos_ohci->clk); + + usb_put_hcd(hcd); + kfree(exynos_ohci); + + return 0; +} + +static void exynos_ohci_shutdown(struct platform_device *pdev) +{ + struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); + struct usb_hcd *hcd = exynos_ohci->hcd; + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); +} + +#ifdef CONFIG_PM +static int exynos_ohci_suspend(struct device *dev) +{ + struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); + struct usb_hcd *hcd = exynos_ohci->hcd; + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + struct platform_device *pdev = to_platform_device(dev); + struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; + unsigned long flags; + int rc = 0; + + /* + * Root hub was already suspended. Disable irq emission and + * mark HW unaccessible, bail out if RH has been resumed. Use + * the spinlock to properly synchronize with possible pending + * RH suspend or resume activity. + * + * This is still racy as hcd->state is manipulated outside of + * any locks =P But that will be a different fix. + */ + spin_lock_irqsave(&ohci->lock, flags); + if (hcd->state != HC_STATE_SUSPENDED && hcd->state != HC_STATE_HALT) { + rc = -EINVAL; + goto fail; + } + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + if (pdata && pdata->phy_exit) + pdata->phy_exit(pdev, S5P_USB_PHY_HOST); +fail: + spin_unlock_irqrestore(&ohci->lock, flags); + + return rc; +} + +static int exynos_ohci_resume(struct device *dev) +{ + struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); + struct usb_hcd *hcd = exynos_ohci->hcd; + struct platform_device *pdev = to_platform_device(dev); + struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; + + if (pdata && pdata->phy_init) + pdata->phy_init(pdev, S5P_USB_PHY_HOST); + + /* Mark hardware accessible again as we are out of D3 state by now */ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + ohci_finish_controller_resume(hcd); + + return 0; +} +#else +#define exynos_ohci_suspend NULL +#define exynos_ohci_resume NULL +#endif + +static const struct dev_pm_ops exynos_ohci_pm_ops = { + .suspend = exynos_ohci_suspend, + .resume = exynos_ohci_resume, +}; + +static struct platform_driver exynos_ohci_driver = { + .probe = exynos_ohci_probe, + .remove = __devexit_p(exynos_ohci_remove), + .shutdown = exynos_ohci_shutdown, + .driver = { + .name = "exynos-ohci", + .owner = THIS_MODULE, + .pm = &exynos_ohci_pm_ops, + } +}; + +MODULE_ALIAS("platform:exynos-ohci"); +MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 4fa5d8c4d239..5f5a63241436 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1005,6 +1005,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_s3c2410_driver #endif +#ifdef CONFIG_USB_OHCI_EXYNOS +#include "ohci-exynos.c" +#define PLATFORM_DRIVER exynos_ohci_driver +#endif + #ifdef CONFIG_USB_OHCI_HCD_OMAP1 #include "ohci-omap.c" #define OMAP1_PLATFORM_DRIVER ohci_hcd_omap_driver diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c index 516ebc4d6cc2..1b8133b6e451 100644 --- a/drivers/usb/host/ohci-omap3.c +++ b/drivers/usb/host/ohci-omap3.c @@ -31,6 +31,7 @@ #include <linux/platform_device.h> #include <plat/usb.h> +#include <linux/pm_runtime.h> /*-------------------------------------------------------------------------*/ @@ -134,7 +135,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev) int irq; if (usb_disabled()) - goto err_end; + return -ENODEV; if (!dev->parent) { dev_err(dev, "Missing parent device\n"); @@ -172,11 +173,8 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev) hcd->rsrc_len = resource_size(res); hcd->regs = regs; - ret = omap_usbhs_enable(dev); - if (ret) { - dev_dbg(dev, "failed to start ohci\n"); - goto err_end; - } + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); ohci_hcd_init(hcd_to_ohci(hcd)); @@ -189,9 +187,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev) return 0; err_add_hcd: - omap_usbhs_disable(dev); - -err_end: + pm_runtime_put_sync(dev); usb_put_hcd(hcd); err_io: @@ -220,9 +216,9 @@ static int __devexit ohci_hcd_omap3_remove(struct platform_device *pdev) iounmap(hcd->regs); usb_remove_hcd(hcd); - omap_usbhs_disable(dev); + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); usb_put_hcd(hcd); - return 0; } |