diff options
Diffstat (limited to 'drivers')
32 files changed, 888 insertions, 107 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 423fd56bf612..43643033a3ae 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -298,7 +298,7 @@ if RTC_LIB=n config RTC tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)" depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \ - && !ARM && !SUPERH && !S390 && !AVR32 && !BLACKFIN + && !ARM && !SUPERH && !S390 && !AVR32 && !BLACKFIN && !UML ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -346,7 +346,7 @@ config JS_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32 && !BLACKFIN + depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32 && !BLACKFIN && !UML ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -490,7 +490,7 @@ config SCx200_GPIO config PC8736x_GPIO tristate "NatSemi PC8736x GPIO Support" - depends on X86_32 + depends on X86_32 && !UML default SCx200_GPIO # mostly N select NSC_GPIO # needed for support routines help diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 1d2ebc7a4947..0689bf6b0183 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -60,6 +60,19 @@ config HW_RANDOM_AMD If unsure, say Y. +config HW_RANDOM_ATMEL + tristate "Atmel Random Number Generator support" + depends on HW_RANDOM && ARCH_AT91SAM9G45 + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on Atmel AT91 devices. + + To compile this driver as a module, choose M here: the + module will be called atmel-rng. + + If unsure, say Y. + config HW_RANDOM_GEODE tristate "AMD Geode HW Random Number Generator support" depends on HW_RANDOM && X86_32 && PCI @@ -222,3 +235,18 @@ config HW_RANDOM_PPC4XX module will be called ppc4xx-rng. If unsure, say N. + +config UML_RANDOM + depends on UML + tristate "Hardware random number generator" + help + This option enables UML's "hardware" random number generator. It + attaches itself to the host's /dev/random, supplying as much entropy + as the host has, rather than the small amount the UML gets from its + own drivers. It registers itself as a standard hardware random number + generator, major 10, minor 183, and the canonical device name is + /dev/hwrng. + The way to make use of this is to install the rng-tools package + (check your distro, or download from + http://sourceforge.net/projects/gkernel/). rngd periodically reads + /dev/hwrng and injects the entropy into /dev/random. diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index c88f244c8a71..b2ff5265a996 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -7,6 +7,7 @@ rng-core-y := core.o obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o +obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o n2-rng-y := n2-drv.o n2-asm.o diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c new file mode 100644 index 000000000000..241df2e76aba --- /dev/null +++ b/drivers/char/hw_random/atmel-rng.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2011 Peter Korsgaard <jacmet@sunsite.dk> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/hw_random.h> +#include <linux/platform_device.h> + +#define TRNG_CR 0x00 +#define TRNG_ISR 0x1c +#define TRNG_ODATA 0x50 + +#define TRNG_KEY 0x524e4700 /* RNG */ + +struct atmel_trng { + struct clk *clk; + void __iomem *base; + struct hwrng rng; +}; + +static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max, + bool wait) +{ + struct atmel_trng *trng = container_of(rng, struct atmel_trng, rng); + u32 *data = buf; + + /* data ready? */ + if (readl(trng->base + TRNG_ODATA) & 1) { + *data = readl(trng->base + TRNG_ODATA); + return 4; + } else + return 0; +} + +static int atmel_trng_probe(struct platform_device *pdev) +{ + struct atmel_trng *trng; + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); + if (!trng) + return -ENOMEM; + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), pdev->name)) + return -EBUSY; + + trng->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!trng->base) + return -EBUSY; + + trng->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(trng->clk)) + return PTR_ERR(trng->clk); + + ret = clk_enable(trng->clk); + if (ret) + goto err_enable; + + writel(TRNG_KEY | 1, trng->base + TRNG_CR); + trng->rng.name = pdev->name; + trng->rng.read = atmel_trng_read; + + ret = hwrng_register(&trng->rng); + if (ret) + goto err_register; + + platform_set_drvdata(pdev, trng); + + return 0; + +err_register: + clk_disable(trng->clk); +err_enable: + clk_put(trng->clk); + + return ret; +} + +static int __devexit atmel_trng_remove(struct platform_device *pdev) +{ + struct atmel_trng *trng = platform_get_drvdata(pdev); + + hwrng_unregister(&trng->rng); + + writel(TRNG_KEY, trng->base + TRNG_CR); + clk_disable(trng->clk); + clk_put(trng->clk); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int atmel_trng_suspend(struct device *dev) +{ + struct atmel_trng *trng = dev_get_drvdata(dev); + + clk_disable(trng->clk); + + return 0; +} + +static int atmel_trng_resume(struct device *dev) +{ + struct atmel_trng *trng = dev_get_drvdata(dev); + + return clk_enable(trng->clk); +} + +static const struct dev_pm_ops atmel_trng_pm_ops = { + .suspend = atmel_trng_suspend, + .resume = atmel_trng_resume, +}; +#endif /* CONFIG_PM */ + +static struct platform_driver atmel_trng_driver = { + .probe = atmel_trng_probe, + .remove = __devexit_p(atmel_trng_remove), + .driver = { + .name = "atmel-trng", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &atmel_trng_pm_ops, +#endif /* CONFIG_PM */ + }, +}; + +static int __init atmel_trng_init(void) +{ + return platform_driver_register(&atmel_trng_driver); +} +module_init(atmel_trng_init); + +static void __exit atmel_trng_exit(void) +{ + platform_driver_unregister(&atmel_trng_driver); +} +module_exit(atmel_trng_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); +MODULE_DESCRIPTION("Atmel true random number generator driver"); diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index a1f68af4ccf4..f22861511909 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -170,7 +170,7 @@ static const struct tty_operations ttyprintk_ops = { .ioctl = tpk_ioctl, }; -struct tty_port_operations null_ops = { }; +static struct tty_port_operations null_ops = { }; static struct tty_driver *ttyprintk_driver; diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 34e9c4f88926..999d6a03e436 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -15,3 +15,18 @@ config CLKSRC_MMIO config DW_APB_TIMER bool + +config CLKSRC_DBX500_PRCMU + bool "Clocksource PRCMU Timer" + depends on UX500_SOC_DB5500 || UX500_SOC_DB8500 + default y + help + Use the always on PRCMU Timer as clocksource + +config CLKSRC_DBX500_PRCMU_SCHED_CLOCK + bool "Clocksource PRCMU Timer sched_clock" + depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK) + select HAVE_SCHED_CLOCK + default y + help + Use the always on PRCMU Timer as sched_clock diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 85ad1646a7b7..8d81a1d32653 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o +obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
\ No newline at end of file diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c new file mode 100644 index 000000000000..59feefe0e3e6 --- /dev/null +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson + * Author: Sundar Iyer for ST-Ericsson + * sched_clock implementation is based on: + * plat-nomadik/timer.c Linus Walleij <linus.walleij@stericsson.com> + * + * DBx500-PRCMU Timer + * The PRCMU has 5 timers which are available in a always-on + * power domain. We use the Timer 4 for our always-on clock + * source on DB8500 and Timer 3 on DB5500. + */ +#include <linux/clockchips.h> +#include <linux/clksrc-dbx500-prcmu.h> + +#include <asm/sched_clock.h> + +#include <mach/setup.h> +#include <mach/hardware.h> + +#define RATE_32K 32768 + +#define TIMER_MODE_CONTINOUS 0x1 +#define TIMER_DOWNCOUNT_VAL 0xffffffff + +#define PRCMU_TIMER_REF 0 +#define PRCMU_TIMER_DOWNCOUNT 0x4 +#define PRCMU_TIMER_MODE 0x8 + +#define SCHED_CLOCK_MIN_WRAP 131072 /* 2^32 / 32768 */ + +static void __iomem *clksrc_dbx500_timer_base; + +static cycle_t clksrc_dbx500_prcmu_read(struct clocksource *cs) +{ + u32 count, count2; + + do { + count = readl(clksrc_dbx500_timer_base + + PRCMU_TIMER_DOWNCOUNT); + count2 = readl(clksrc_dbx500_timer_base + + PRCMU_TIMER_DOWNCOUNT); + } while (count2 != count); + + /* Negate because the timer is a decrementing counter */ + return ~count; +} + +static struct clocksource clocksource_dbx500_prcmu = { + .name = "dbx500-prcmu-timer", + .rating = 300, + .read = clksrc_dbx500_prcmu_read, + .shift = 10, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +#ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK +static DEFINE_CLOCK_DATA(cd); + +unsigned long long notrace sched_clock(void) +{ + u32 cyc; + + if (unlikely(!clksrc_dbx500_timer_base)) + return 0; + + cyc = clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu); + + return cyc_to_sched_clock(&cd, cyc, (u32)~0); +} + +static void notrace clksrc_dbx500_prcmu_update_sched_clock(void) +{ + u32 cyc = clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu); + update_sched_clock(&cd, cyc, (u32)~0); +} +#endif + +void __init clksrc_dbx500_prcmu_init(void __iomem *base) +{ + clksrc_dbx500_timer_base = base; + + /* + * The A9 sub system expects the timer to be configured as + * a continous looping timer. + * The PRCMU should configure it but if it for some reason + * don't we do it here. + */ + if (readl(clksrc_dbx500_timer_base + PRCMU_TIMER_MODE) != + TIMER_MODE_CONTINOUS) { + writel(TIMER_MODE_CONTINOUS, + clksrc_dbx500_timer_base + PRCMU_TIMER_MODE); + writel(TIMER_DOWNCOUNT_VAL, + clksrc_dbx500_timer_base + PRCMU_TIMER_REF); + } +#ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK + init_sched_clock(&cd, clksrc_dbx500_prcmu_update_sched_clock, + 32, RATE_32K); +#endif + clocksource_calc_mult_shift(&clocksource_dbx500_prcmu, + RATE_32K, SCHED_CLOCK_MIN_WRAP); + clocksource_register(&clocksource_dbx500_prcmu); +} diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 82f7b65baf72..b81c98992114 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -32,6 +32,8 @@ #include <asm-generic/bug.h> #include <asm/mach/irq.h> +#define irq_to_gpio(irq) ((irq) - MXC_GPIO_IRQ_START) + enum mxc_gpio_hwtype { IMX1_GPIO, /* runs on i.mx1 */ IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ @@ -343,6 +345,15 @@ static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) mxc_gpio_hwtype = hwtype; } +static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + struct mxc_gpio_port *port = + container_of(bgc, struct mxc_gpio_port, bgc); + + return port->virtual_irq_start + offset; +} + static int __devinit mxc_gpio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -409,6 +420,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) if (err) goto out_iounmap; + port->bgc.gc.to_irq = mxc_gpio_to_irq; port->bgc.gc.base = pdev->id * 32; port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir); port->bgc.data = port->bgc.read_reg(port->bgc.reg_set); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index af55a8577c2e..292b50481db9 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -49,6 +49,8 @@ #define GPIO_INT_LEV_MASK (1 << 0) #define GPIO_INT_POL_MASK (1 << 1) +#define irq_to_gpio(irq) ((irq) - MXS_GPIO_IRQ_START) + struct mxs_gpio_port { void __iomem *base; int id; diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 9052925c6fa2..ee137712f9db 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -122,7 +122,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 = (void __iomem *)GPIO_BANK(i); + chips[i].regbase = GPIO_BANK(i); c->base = gpio; c->label = chips[i].label; diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 6b65207c8106..61044c889f7f 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -20,10 +20,11 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/interrupt.h> - #include <linux/io.h> #include <linux/gpio.h> #include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/module.h> #include <asm/mach/irq.h> @@ -35,9 +36,7 @@ #define GPIO_PORT(x) (((x) >> 3) & 0x3) #define GPIO_BIT(x) ((x) & 0x7) -#define GPIO_REG(x) (IO_TO_VIRT(TEGRA_GPIO_BASE) + \ - GPIO_BANK(x) * 0x80 + \ - GPIO_PORT(x) * 4) +#define GPIO_REG(x) (GPIO_BANK(x) * 0x80 + GPIO_PORT(x) * 4) #define GPIO_CNF(x) (GPIO_REG(x) + 0x00) #define GPIO_OE(x) (GPIO_REG(x) + 0x10) @@ -76,15 +75,18 @@ struct tegra_gpio_bank { }; -static struct tegra_gpio_bank tegra_gpio_banks[] = { - {.bank = 0, .irq = INT_GPIO1}, - {.bank = 1, .irq = INT_GPIO2}, - {.bank = 2, .irq = INT_GPIO3}, - {.bank = 3, .irq = INT_GPIO4}, - {.bank = 4, .irq = INT_GPIO5}, - {.bank = 5, .irq = INT_GPIO6}, - {.bank = 6, .irq = INT_GPIO7}, -}; +static void __iomem *regs; +static struct tegra_gpio_bank tegra_gpio_banks[7]; + +static inline void tegra_gpio_writel(u32 val, u32 reg) +{ + __raw_writel(val, regs + reg); +} + +static inline u32 tegra_gpio_readl(u32 reg) +{ + return __raw_readl(regs + reg); +} static int tegra_gpio_compose(int bank, int port, int bit) { @@ -98,7 +100,7 @@ static void tegra_gpio_mask_write(u32 reg, int gpio, int value) val = 0x100 << GPIO_BIT(gpio); if (value) val |= 1 << GPIO_BIT(gpio); - __raw_writel(val, reg); + tegra_gpio_writel(val, reg); } void tegra_gpio_enable(int gpio) @@ -118,7 +120,7 @@ static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) { - return (__raw_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; + return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; } static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -155,7 +157,7 @@ static void tegra_gpio_irq_ack(struct irq_data *d) { int gpio = d->irq - INT_GPIO_BASE; - __raw_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); + tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); } static void tegra_gpio_irq_mask(struct irq_data *d) @@ -208,10 +210,10 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) spin_lock_irqsave(&bank->lvl_lock[port], flags); - val = __raw_readl(GPIO_INT_LVL(gpio)); + val = tegra_gpio_readl(GPIO_INT_LVL(gpio)); val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio)); val |= lvl_type << GPIO_BIT(gpio); - __raw_writel(val, GPIO_INT_LVL(gpio)); + tegra_gpio_writel(val, GPIO_INT_LVL(gpio)); spin_unlock_irqrestore(&bank->lvl_lock[port], flags); @@ -237,12 +239,12 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) for (port = 0; port < 4; port++) { int gpio = tegra_gpio_compose(bank->bank, port, 0); - unsigned long sta = __raw_readl(GPIO_INT_STA(gpio)) & - __raw_readl(GPIO_INT_ENB(gpio)); - u32 lvl = __raw_readl(GPIO_INT_LVL(gpio)); + unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) & + tegra_gpio_readl(GPIO_INT_ENB(gpio)); + u32 lvl = tegra_gpio_readl(GPIO_INT_LVL(gpio)); for_each_set_bit(pin, &sta, 8) { - __raw_writel(1 << pin, GPIO_INT_CLR(gpio)); + tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio)); /* if gpio is edge triggered, clear condition * before executing the hander so that we don't @@ -276,11 +278,11 @@ void tegra_gpio_resume(void) for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { unsigned int gpio = (b<<5) | (p<<3); - __raw_writel(bank->cnf[p], GPIO_CNF(gpio)); - __raw_writel(bank->out[p], GPIO_OUT(gpio)); - __raw_writel(bank->oe[p], GPIO_OE(gpio)); - __raw_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio)); - __raw_writel(bank->int_enb[p], GPIO_INT_ENB(gpio)); + tegra_gpio_writel(bank->cnf[p], GPIO_CNF(gpio)); + tegra_gpio_writel(bank->out[p], GPIO_OUT(gpio)); + tegra_gpio_writel(bank->oe[p], GPIO_OE(gpio)); + tegra_gpio_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio)); + tegra_gpio_writel(bank->int_enb[p], GPIO_INT_ENB(gpio)); } } @@ -299,11 +301,11 @@ void tegra_gpio_suspend(void) for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { unsigned int gpio = (b<<5) | (p<<3); - bank->cnf[p] = __raw_readl(GPIO_CNF(gpio)); - bank->out[p] = __raw_readl(GPIO_OUT(gpio)); - bank->oe[p] = __raw_readl(GPIO_OE(gpio)); - bank->int_enb[p] = __raw_readl(GPIO_INT_ENB(gpio)); - bank->int_lvl[p] = __raw_readl(GPIO_INT_LVL(gpio)); + bank->cnf[p] = tegra_gpio_readl(GPIO_CNF(gpio)); + bank->out[p] = tegra_gpio_readl(GPIO_OUT(gpio)); + bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio)); + bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio)); + bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio)); } } local_irq_restore(flags); @@ -333,28 +335,55 @@ static struct irq_chip tegra_gpio_irq_chip = { */ static struct lock_class_key gpio_lock_class; -static int __init tegra_gpio_init(void) +static int __devinit tegra_gpio_probe(struct platform_device *pdev) { + struct resource *res; struct tegra_gpio_bank *bank; int gpio; int i; int j; + for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + if (!res) { + dev_err(&pdev->dev, "Missing IRQ resource\n"); + return -ENODEV; + } + + bank = &tegra_gpio_banks[i]; + bank->bank = i; + bank->irq = res->start; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Missing MEM resource\n"); + return -ENODEV; + } + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "Couldn't request MEM resource\n"); + return -ENODEV; + } + + regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!regs) { + dev_err(&pdev->dev, "Couldn't ioremap regs\n"); + return -ENODEV; + } + for (i = 0; i < 7; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); - __raw_writel(0x00, GPIO_INT_ENB(gpio)); + tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio)); } } #ifdef CONFIG_OF_GPIO - /* - * This isn't ideal, but it gets things hooked up until this - * driver is converted into a platform_device - */ - tegra_gpio_chip.of_node = of_find_compatible_node(NULL, NULL, - "nvidia,tegra20-gpio"); -#endif /* CONFIG_OF_GPIO */ + tegra_gpio_chip.of_node = pdev->dev.of_node; +#endif gpiochip_add(&tegra_gpio_chip); @@ -384,6 +413,24 @@ static int __init tegra_gpio_init(void) return 0; } +static struct of_device_id tegra_gpio_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra20-gpio", }, + { }, +}; + +static struct platform_driver tegra_gpio_driver = { + .driver = { + .name = "tegra-gpio", + .owner = THIS_MODULE, + .of_match_table = tegra_gpio_of_match, + }, + .probe = tegra_gpio_probe, +}; + +static int __init tegra_gpio_init(void) +{ + return platform_driver_register(&tegra_gpio_driver); +} postcore_initcall(tegra_gpio_init); void __init tegra_gpio_config(struct tegra_gpio_table *table, int num) @@ -416,13 +463,13 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) seq_printf(s, "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", i, j, - __raw_readl(GPIO_CNF(gpio)), - __raw_readl(GPIO_OE(gpio)), - __raw_readl(GPIO_OUT(gpio)), - __raw_readl(GPIO_IN(gpio)), - __raw_readl(GPIO_INT_STA(gpio)), - __raw_readl(GPIO_INT_ENB(gpio)), - __raw_readl(GPIO_INT_LVL(gpio))); + tegra_gpio_readl(GPIO_CNF(gpio)), + tegra_gpio_readl(GPIO_OE(gpio)), + tegra_gpio_readl(GPIO_OUT(gpio)), + tegra_gpio_readl(GPIO_IN(gpio)), + tegra_gpio_readl(GPIO_INT_STA(gpio)), + tegra_gpio_readl(GPIO_INT_ENB(gpio)), + tegra_gpio_readl(GPIO_INT_LVL(gpio))); } } return 0; diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 23e82e46656d..001b147c7f95 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -3,7 +3,7 @@ # menu "Input device support" - depends on !S390 + depends on !S390 && !UML config INPUT tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 4fb601670de3..a233ed53913a 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -5,7 +5,7 @@ menuconfig ISDN bool "ISDN support" depends on NET - depends on !S390 + depends on !S390 && !UML ---help--- ISDN ("Integrated Services Digital Network", called RNIS in France) is a fully digital telephone service that can be used for voice and diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 50d5f27f09d0..d593878d66d0 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -63,7 +63,7 @@ config AD525X_DPOT_SPI config ATMEL_PWM tristate "Atmel AT32/AT91 PWM support" - depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 + depends on HAVE_CLK help This option enables device driver support for the PWM channels on certain Atmel processors. Pulse Width Modulation is used for diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 0076c7448fe6..64a8325a4a8a 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -807,12 +807,25 @@ static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios) static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmc_davinci_host *host = mmc_priv(mmc); + struct platform_device *pdev = to_platform_device(mmc->parent); + struct davinci_mmc_config *config = pdev->dev.platform_data; dev_dbg(mmc_dev(host->mmc), "clock %dHz busmode %d powermode %d Vdd %04x\n", ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); + switch (ios->power_mode) { + case MMC_POWER_OFF: + if (config && config->set_power) + config->set_power(pdev->id, false); + break; + case MMC_POWER_UP: + if (config && config->set_power) + config->set_power(pdev->id, true); + break; + } + switch (ios->bus_width) { case MMC_BUS_WIDTH_8: dev_dbg(mmc_dev(host->mmc), "Enabling 8 bit mode\n"); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index f48743de4673..325ea61e12d3 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -40,6 +40,7 @@ #include <mach/mmc.h> #include <mach/dma.h> +#include <mach/hardware.h> #define DRIVER_NAME "mxc-mmc" diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index f1af2228a1b1..61086ea3cc6b 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1144,7 +1144,7 @@ static void mtdchar_notify_remove(struct mtd_info *mtd) if (mtd_ino) { /* Destroy the inode if it exists */ - mtd_ino->i_nlink = 0; + clear_nlink(mtd_ino); iput(mtd_ino); } } diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 073548836413..09602241901b 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,6 +1,6 @@ menuconfig ATH_COMMON tristate "Atheros Wireless Cards" - depends on CFG80211 + depends on CFG80211 && (!UML || BROKEN) ---help--- This will enable the support for the Atheros wireless drivers. ath5k, ath9k, ath9k_htc and ar9170 drivers share some common code, this option diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index 45e14760c16e..d6c42e69bdbd 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -12,7 +12,7 @@ config RTL8192CE config RTL8192SE tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" - depends on MAC80211 && EXPERIMENTAL + depends on MAC80211 && EXPERIMENTAL && PCI select FW_LOADER select RTLWIFI ---help--- @@ -23,7 +23,7 @@ config RTL8192SE config RTL8192DE tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" - depends on MAC80211 && EXPERIMENTAL + depends on MAC80211 && EXPERIMENTAL && PCI select FW_LOADER select RTLWIFI ---help--- diff --git a/drivers/of/base.c b/drivers/of/base.c index b970562e0111..9b6588ef0673 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -716,6 +716,90 @@ int of_property_read_string(struct device_node *np, const char *propname, EXPORT_SYMBOL_GPL(of_property_read_string); /** + * of_property_read_string_index - Find and read a string from a multiple + * strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @index: index of the string in the list of strings + * @out_string: pointer to null terminated return string, modified only if + * return value is 0. + * + * Search for a property in a device tree node and retrieve a null + * terminated string value (pointer to data, not a copy) in the list of strings + * contained in that property. + * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if + * property does not have a value, and -EILSEQ if the string is not + * null-terminated within the length of the property data. + * + * The out_string pointer is modified only if a valid string can be decoded. + */ +int of_property_read_string_index(struct device_node *np, const char *propname, + int index, const char **output) +{ + struct property *prop = of_find_property(np, propname, NULL); + int i = 0; + size_t l = 0, total = 0; + const char *p; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if (strnlen(prop->value, prop->length) >= prop->length) + return -EILSEQ; + + p = prop->value; + + for (i = 0; total < prop->length; total += l, p += l) { + l = strlen(p) + 1; + if ((*p != 0) && (i++ == index)) { + *output = p; + return 0; + } + } + return -ENODATA; +} +EXPORT_SYMBOL_GPL(of_property_read_string_index); + + +/** + * of_property_count_strings - Find and return the number of strings from a + * multiple strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * + * Search for a property in a device tree node and retrieve the number of null + * terminated string contain in it. Returns the number of strings on + * success, -EINVAL if the property does not exist, -ENODATA if property + * does not have a value, and -EILSEQ if the string is not null-terminated + * within the length of the property data. + */ +int of_property_count_strings(struct device_node *np, const char *propname) +{ + struct property *prop = of_find_property(np, propname, NULL); + int i = 0; + size_t l = 0, total = 0; + const char *p; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if (strnlen(prop->value, prop->length) >= prop->length) + return -EILSEQ; + + p = prop->value; + + for (i = 0; total < prop->length; total += l, p += l) { + l = strlen(p) + 1; + if (*p != 0) + i++; + } + return i; +} +EXPORT_SYMBOL_GPL(of_property_count_strings); + +/** * of_parse_phandle - Resolve a phandle property to a device_node pointer * @np: Pointer to device node holding phandle property * @phandle_name: Name of property holding a phandle value diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 6a5b5e777dd2..6d3dd3988d0f 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -19,10 +19,12 @@ */ #include <linux/errno.h> +#include <linux/list.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/string.h> +#include <linux/slab.h> /* For archs that don't support NO_IRQ (such as x86), provide a dummy value */ #ifndef NO_IRQ @@ -386,3 +388,108 @@ int of_irq_to_resource_table(struct device_node *dev, struct resource *res, return i; } + +struct intc_desc { + struct list_head list; + struct device_node *dev; + struct device_node *interrupt_parent; +}; + +/** + * of_irq_init - Scan and init matching interrupt controllers in DT + * @matches: 0 terminated array of nodes to match and init function to call + * + * This function scans the device tree for matching interrupt controller nodes, + * and calls their initialization functions in order with parents first. + */ +void __init of_irq_init(const struct of_device_id *matches) +{ + struct device_node *np, *parent = NULL; + struct intc_desc *desc, *temp_desc; + struct list_head intc_desc_list, intc_parent_list; + + INIT_LIST_HEAD(&intc_desc_list); + INIT_LIST_HEAD(&intc_parent_list); + + for_each_matching_node(np, matches) { + if (!of_find_property(np, "interrupt-controller", NULL)) + continue; + /* + * Here, we allocate and populate an intc_desc with the node + * pointer, interrupt-parent device_node etc. + */ + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (WARN_ON(!desc)) + goto err; + + desc->dev = np; + desc->interrupt_parent = of_irq_find_parent(np); + list_add_tail(&desc->list, &intc_desc_list); + } + + /* + * The root irq controller is the one without an interrupt-parent. + * That one goes first, followed by the controllers that reference it, + * followed by the ones that reference the 2nd level controllers, etc. + */ + while (!list_empty(&intc_desc_list)) { + /* + * Process all controllers with the current 'parent'. + * First pass will be looking for NULL as the parent. + * The assumption is that NULL parent means a root controller. + */ + list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) { + const struct of_device_id *match; + int ret; + of_irq_init_cb_t irq_init_cb; + + if (desc->interrupt_parent != parent) + continue; + + list_del(&desc->list); + match = of_match_node(matches, desc->dev); + if (WARN(!match->data, + "of_irq_init: no init function for %s\n", + match->compatible)) { + kfree(desc); + continue; + } + + pr_debug("of_irq_init: init %s @ %p, parent %p\n", + match->compatible, + desc->dev, desc->interrupt_parent); + irq_init_cb = match->data; + ret = irq_init_cb(desc->dev, desc->interrupt_parent); + if (ret) { + kfree(desc); + continue; + } + + /* + * This one is now set up; add it to the parent list so + * its children can get processed in a subsequent pass. + */ + list_add_tail(&desc->list, &intc_parent_list); + } + + /* Get the next pending parent that might have children */ + desc = list_first_entry(&intc_parent_list, typeof(*desc), list); + if (list_empty(&intc_parent_list) || !desc) { + pr_err("of_irq_init: children remain, but no parents\n"); + break; + } + list_del(&desc->list); + parent = desc->dev; + kfree(desc); + } + + list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) { + list_del(&desc->list); + kfree(desc); + } +err: + list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) { + list_del(&desc->list); + kfree(desc); + } +} diff --git a/drivers/pcmcia/pxa2xx_balloon3.c b/drivers/pcmcia/pxa2xx_balloon3.c index f56d7de7c751..22a75e610f12 100644 --- a/drivers/pcmcia/pxa2xx_balloon3.c +++ b/drivers/pcmcia/pxa2xx_balloon3.c @@ -97,7 +97,7 @@ static void balloon3_pcmcia_socket_state(struct soc_pcmcia_socket *skt, static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { - __raw_writew(BALLOON3_CF_RESET, BALLOON3_CF_CONTROL_REG | + __raw_writew(BALLOON3_CF_RESET, BALLOON3_CF_CONTROL_REG + ((state->flags & SS_RESET) ? BALLOON3_FPGA_SETnCLR : 0)); return 0; diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 57de051a74b3..9f88641e67f9 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -70,6 +70,7 @@ config BATTERY_DS2760 config BATTERY_DS2780 tristate "DS2780 battery driver" + depends on HAS_IOMEM select W1 select W1_SLAVE_DS2780 help diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 5a538fc1cc85..53eb4e55b289 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -8,7 +8,7 @@ config RTC_LIB menuconfig RTC_CLASS bool "Real Time Clock" default n - depends on !S390 + depends on !S390 && !UML select RTC_LIB help Generic RTC class support. If you say yes here, you will diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index f3c6060c96b8..7a1955583b7d 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -1197,7 +1197,7 @@ const struct inode_operations pohmelfs_file_inode_operations = { void pohmelfs_fill_inode(struct inode *inode, struct netfs_inode_info *info) { inode->i_mode = info->mode; - inode->i_nlink = info->nlink; + set_nlink(inode, info->nlink); inode->i_uid = info->uid; inode->i_gid = info->gid; inode->i_blocks = info->blocks; diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 8816f53e004d..b3d17416d86a 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -1,6 +1,6 @@ config VT bool "Virtual terminal" if EXPERT - depends on !S390 + depends on !S390 && !UML select INPUT default y ---help--- diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 29cbfd8c4e7c..8131e2c28015 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -19,6 +19,7 @@ # define SUPPORT_SYSRQ #endif +#include <linux/atomic.h> #include <linux/hrtimer.h> #include <linux/module.h> #include <linux/io.h> @@ -33,6 +34,8 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_device.h> #include "msm_serial.h" @@ -589,9 +592,8 @@ static void msm_release_port(struct uart_port *port) iowrite32(GSBI_PROTOCOL_IDLE, msm_port->gsbi_base + GSBI_CONTROL); - gsbi_resource = platform_get_resource_byname(pdev, - IORESOURCE_MEM, - "gsbi_resource"); + gsbi_resource = platform_get_resource(pdev, + IORESOURCE_MEM, 1); if (unlikely(!gsbi_resource)) return; @@ -612,8 +614,7 @@ static int msm_request_port(struct uart_port *port) resource_size_t size; int ret; - uart_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "uart_resource"); + uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!uart_resource)) return -ENXIO; @@ -628,8 +629,7 @@ static int msm_request_port(struct uart_port *port) goto fail_release_port; } - gsbi_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "gsbi_resource"); + gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1); /* Is this a GSBI-based port? */ if (gsbi_resource) { size = resource_size(gsbi_resource); @@ -857,6 +857,8 @@ static struct uart_driver msm_uart_driver = { .cons = MSM_CONSOLE, }; +static atomic_t msm_uart_next_id = ATOMIC_INIT(0); + static int __init msm_serial_probe(struct platform_device *pdev) { struct msm_port *msm_port; @@ -864,6 +866,9 @@ static int __init msm_serial_probe(struct platform_device *pdev) struct uart_port *port; int irq; + if (pdev->id == -1) + pdev->id = atomic_inc_return(&msm_uart_next_id) - 1; + if (unlikely(pdev->id < 0 || pdev->id >= UART_NR)) return -ENXIO; @@ -873,7 +878,7 @@ static int __init msm_serial_probe(struct platform_device *pdev) port->dev = &pdev->dev; msm_port = UART_TO_MSM(port); - if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsbi_resource")) + if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) msm_port->is_uartdm = 1; else msm_port->is_uartdm = 0; @@ -897,8 +902,7 @@ static int __init msm_serial_probe(struct platform_device *pdev) printk(KERN_INFO "uartclk = %d\n", port->uartclk); - resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "uart_resource"); + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!resource)) return -ENXIO; port->mapbase = resource->start; @@ -922,11 +926,17 @@ static int __devexit msm_serial_remove(struct platform_device *pdev) return 0; } +static struct of_device_id msm_match_table[] = { + { .compatible = "qcom,msm-uart" }, + {} +}; + static struct platform_driver msm_platform_driver = { .remove = msm_serial_remove, .driver = { .name = "msm_serial", .owner = THIS_MODULE, + .of_match_table = msm_match_table, }, }; diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 944291e10f97..ba3a46b78b75 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -35,8 +35,7 @@ extern int usb_disabled(void); static void at91_start_clock(void) { - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - clk_enable(hclk); + clk_enable(hclk); clk_enable(iclk); clk_enable(fclk); clocked = 1; @@ -46,8 +45,7 @@ static void at91_stop_clock(void) { clk_disable(fclk); clk_disable(iclk); - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - clk_disable(hclk); + clk_disable(hclk); clocked = 0; } @@ -142,8 +140,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, iclk = clk_get(&pdev->dev, "ohci_clk"); fclk = clk_get(&pdev->dev, "uhpck"); - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - hclk = clk_get(&pdev->dev, "hck0"); + hclk = clk_get(&pdev->dev, "hclk"); at91_start_hc(pdev); ohci_hcd_init(hcd_to_ohci(hcd)); @@ -155,8 +152,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, /* Error handling */ at91_stop_hc(pdev); - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - clk_put(hclk); + clk_put(hclk); clk_put(fclk); clk_put(iclk); @@ -192,8 +188,7 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd, release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - clk_put(hclk); + clk_put(hclk); clk_put(fclk); clk_put(iclk); fclk = iclk = hclk = NULL; @@ -223,6 +218,156 @@ ohci_at91_start (struct usb_hcd *hcd) return 0; } +static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) +{ + if (port < 0 || port >= 2) + return; + + gpio_set_value(pdata->vbus_pin[port], !pdata->vbus_pin_inverted ^ enable); +} + +static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) +{ + if (port < 0 || port >= 2) + return -EINVAL; + + return gpio_get_value(pdata->vbus_pin[port]) ^ !pdata->vbus_pin_inverted; +} + +/* + * Update the status data from the hub with the over-current indicator change. + */ +static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct at91_usbh_data *pdata = hcd->self.controller->platform_data; + int length = ohci_hub_status_data(hcd, buf); + int port; + + for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) { + if (pdata->overcurrent_changed[port]) { + if (! length) + length = 1; + buf[0] |= 1 << (port + 1); + } + } + + return length; +} + +/* + * Look at the control requests to the root hub and see if we need to override. + */ +static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength) +{ + struct at91_usbh_data *pdata = hcd->self.controller->platform_data; + struct usb_hub_descriptor *desc; + int ret = -EINVAL; + u32 *data = (u32 *)buf; + + dev_dbg(hcd->self.controller, + "ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", + hcd, typeReq, wValue, wIndex, buf, wLength); + + switch (typeReq) { + case SetPortFeature: + if (wValue == USB_PORT_FEAT_POWER) { + dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); + ohci_at91_usb_set_power(pdata, wIndex - 1, 1); + goto out; + } + break; + + case ClearPortFeature: + switch (wValue) { + case USB_PORT_FEAT_C_OVER_CURRENT: + dev_dbg(hcd->self.controller, + "ClearPortFeature: C_OVER_CURRENT\n"); + + if (wIndex == 1 || wIndex == 2) { + pdata->overcurrent_changed[wIndex-1] = 0; + pdata->overcurrent_status[wIndex-1] = 0; + } + + goto out; + + case USB_PORT_FEAT_OVER_CURRENT: + dev_dbg(hcd->self.controller, + "ClearPortFeature: OVER_CURRENT\n"); + + if (wIndex == 1 || wIndex == 2) { + pdata->overcurrent_status[wIndex-1] = 0; + } + + goto out; + + case USB_PORT_FEAT_POWER: + dev_dbg(hcd->self.controller, + "ClearPortFeature: POWER\n"); + + if (wIndex == 1 || wIndex == 2) { + ohci_at91_usb_set_power(pdata, wIndex - 1, 0); + return 0; + } + } + break; + } + + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); + if (ret) + goto out; + + switch (typeReq) { + case GetHubDescriptor: + + /* update the hub's descriptor */ + + desc = (struct usb_hub_descriptor *)buf; + + dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n", + desc->wHubCharacteristics); + + /* remove the old configurations for power-switching, and + * over-current protection, and insert our new configuration + */ + + desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); + desc->wHubCharacteristics |= cpu_to_le16(0x0001); + + if (pdata->overcurrent_supported) { + desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM); + desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001); + } + + dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n", + desc->wHubCharacteristics); + + return ret; + + case GetPortStatus: + /* check port status */ + + dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); + + if (wIndex == 1 || wIndex == 2) { + if (! ohci_at91_usb_get_power(pdata, wIndex-1)) { + *data &= ~cpu_to_le32(RH_PS_PPS); + } + + if (pdata->overcurrent_changed[wIndex-1]) { + *data |= cpu_to_le32(RH_PS_OCIC); + } + + if (pdata->overcurrent_status[wIndex-1]) { + *data |= cpu_to_le32(RH_PS_POCI); + } + } + } + + out: + return ret; +} + /*-------------------------------------------------------------------------*/ static const struct hc_driver ohci_at91_hc_driver = { @@ -258,8 +403,8 @@ static const struct hc_driver ohci_at91_hc_driver = { /* * root hub support */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, + .hub_status_data = ohci_at91_hub_status_data, + .hub_control = ohci_at91_hub_control, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, @@ -269,22 +414,71 @@ static const struct hc_driver ohci_at91_hc_driver = { /*-------------------------------------------------------------------------*/ +static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) +{ + struct platform_device *pdev = data; + struct at91_usbh_data *pdata = pdev->dev.platform_data; + int val, gpio, port; + + /* From the GPIO notifying the over-current situation, find + * out the corresponding port */ + gpio = irq_to_gpio(irq); + for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) { + if (pdata->overcurrent_pin[port] == gpio) + break; + } + + if (port == ARRAY_SIZE(pdata->overcurrent_pin)) { + dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n"); + return IRQ_HANDLED; + } + + val = gpio_get_value(gpio); + + /* When notified of an over-current situation, disable power + on the corresponding port, and mark this port in + over-current. */ + if (! val) { + ohci_at91_usb_set_power(pdata, port, 0); + pdata->overcurrent_status[port] = 1; + pdata->overcurrent_changed[port] = 1; + } + + dev_dbg(& pdev->dev, "overcurrent situation %s\n", + val ? "exited" : "notified"); + + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) { struct at91_usbh_data *pdata = pdev->dev.platform_data; int i; if (pdata) { - /* REVISIT make the driver support per-port power switching, - * and also overcurrent detection. Here we assume the ports - * are always powered while this driver is active, and use - * active-low power switches. - */ for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { if (pdata->vbus_pin[i] <= 0) continue; gpio_request(pdata->vbus_pin[i], "ohci_vbus"); - gpio_direction_output(pdata->vbus_pin[i], 0); + ohci_at91_usb_set_power(pdata, i, 1); + } + + for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) { + int ret; + + if (pdata->overcurrent_pin[i] <= 0) + continue; + gpio_request(pdata->overcurrent_pin[i], "ohci_overcurrent"); + + ret = request_irq(gpio_to_irq(pdata->overcurrent_pin[i]), + ohci_hcd_at91_overcurrent_irq, + IRQF_SHARED, "ohci_overcurrent", pdev); + if (ret) { + gpio_free(pdata->overcurrent_pin[i]); + dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n"); + } } } @@ -301,9 +495,16 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { if (pdata->vbus_pin[i] <= 0) continue; - gpio_direction_output(pdata->vbus_pin[i], 1); + ohci_at91_usb_set_power(pdata, i, 0); gpio_free(pdata->vbus_pin[i]); } + + for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) { + if (pdata->overcurrent_pin[i] <= 0) + continue; + free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev); + gpio_free(pdata->overcurrent_pin[i]); + } } device_init_wakeup(&pdev->dev, 0); diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index afea9abbd678..6ce34160da78 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c @@ -34,7 +34,7 @@ #include "regs.h" #include "reg_bits.h" -static unsigned long virt_base_2700; +static void __iomem *virt_base_2700; #define write_reg(val, reg) do { writel((val), (reg)); } while(0) @@ -850,7 +850,7 @@ static int mbxfb_suspend(struct platform_device *dev, pm_message_t state) { /* make frame buffer memory enter self-refresh mode */ write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR); - while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM) + while (readl(LMPWRSTAT) != LMPWRSTAT_MC_PWR_SRM) ; /* empty statement */ /* reset the device, since it's initial state is 'mostly sleeping' */ @@ -946,7 +946,7 @@ static int __devinit mbxfb_probe(struct platform_device *dev) ret = -EINVAL; goto err3; } - virt_base_2700 = (unsigned long)mfbi->reg_virt_addr; + virt_base_2700 = mfbi->reg_virt_addr; mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr, res_size(mfbi->fb_req)); diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index e89778f4081f..1d1e4f175e78 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -1309,16 +1309,6 @@ static int pxafb_smart_init(struct pxafb_info *fbi) return 0; } #else -int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds) -{ - return 0; -} - -int pxafb_smart_flush(struct fb_info *info) -{ - return 0; -} - static inline int pxafb_smart_init(struct pxafb_info *fbi) { return 0; } #endif /* CONFIG_FB_PXA_SMARTPANEL */ diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 86b0735e6aa0..64c6752ea2c6 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -726,7 +726,7 @@ config SBC8360_WDT config SBC7240_WDT tristate "SBC Nano 7240 Watchdog Timer" - depends on X86_32 + depends on X86_32 && !UML ---help--- This is the driver for the hardware watchdog found on the IEI single board computers EPIC Nano 7240 (and likely others). This @@ -1174,6 +1174,10 @@ config XEN_WDT by Xen 4.0 and newer. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. +config UML_WATCHDOG + tristate "UML watchdog" + depends on UML + # # ISA-based Watchdog Cards # |