diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/corgikbd.c | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/spitzkbd.c | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/corgi_ts.c | 1 | ||||
-rw-r--r-- | drivers/leds/Kconfig | 7 | ||||
-rw-r--r-- | drivers/leds/Makefile | 1 | ||||
-rw-r--r-- | drivers/leds/leds-tosa.c | 130 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 16 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 3 | ||||
-rw-r--r-- | drivers/mfd/htc-egpio.c | 440 | ||||
-rw-r--r-- | drivers/mfd/htc-pasic3.c | 265 | ||||
-rw-r--r-- | drivers/net/arm/at91_ether.c | 4 | ||||
-rw-r--r-- | drivers/net/irda/pxaficp_ir.c | 11 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 5 | ||||
-rw-r--r-- | drivers/pcmcia/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_cm_x270.c | 1 | ||||
-rw-r--r-- | drivers/serial/imx.c | 111 | ||||
-rw-r--r-- | drivers/video/pxafb.c | 1 |
18 files changed, 798 insertions, 202 deletions
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 2d2087a..6fd2d6a 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -39,6 +39,7 @@ #include <asm/io.h> #include <asm/arch/i2c.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> struct pxa_i2c { spinlock_t lock; diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 790fed3..5d6cc7f 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -23,6 +23,7 @@ #include <asm/arch/corgi.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #include <asm/hardware/scoop.h> #define KB_ROWS 8 diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 1d59a2d..0be74bf 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -23,6 +23,7 @@ #include <asm/arch/spitz.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #define KB_ROWS 7 #define KB_COLS 11 diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 99d92f5..a225767 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -22,6 +22,7 @@ #include <asm/arch/sharpsl.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #define PWR_MODE_ACTIVE 0 diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 859814f..a3a6199 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -46,13 +46,6 @@ config LEDS_SPITZ This option enables support for the LEDs on Sharp Zaurus SL-Cxx00 series (C1000, C3000, C3100). -config LEDS_TOSA - tristate "LED Support for the Sharp SL-6000 series" - depends on LEDS_CLASS && PXA_SHARPSL - help - This option enables support for the LEDs on Sharp Zaurus - SL-6000 series. - config LEDS_S3C24XX tristate "LED Support for Samsung S3C24XX GPIO LEDs" depends on LEDS_CLASS && ARCH_S3C2410 diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 84ced3b..e54f42da 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o -obj-$(CONFIG_LEDS_TOSA) += leds-tosa.o obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o diff --git a/drivers/leds/leds-tosa.c b/drivers/leds/leds-tosa.c deleted file mode 100644 index 9e0a188..0000000 --- a/drivers/leds/leds-tosa.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * LED Triggers Core - * - * Copyright 2005 Dirk Opfer - * - * Author: Dirk Opfer <Dirk@Opfer-Online.de> - * based on spitz.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <asm/hardware/scoop.h> -#include <asm/mach-types.h> -#include <asm/arch/hardware.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/tosa.h> - -static void tosaled_amber_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) - set_scoop_gpio(&tosascoop_jc_device.dev, - TOSA_SCOOP_JC_CHRG_ERR_LED); - else - reset_scoop_gpio(&tosascoop_jc_device.dev, - TOSA_SCOOP_JC_CHRG_ERR_LED); -} - -static void tosaled_green_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) - set_scoop_gpio(&tosascoop_jc_device.dev, - TOSA_SCOOP_JC_NOTE_LED); - else - reset_scoop_gpio(&tosascoop_jc_device.dev, - TOSA_SCOOP_JC_NOTE_LED); -} - -static struct led_classdev tosa_amber_led = { - .name = "tosa:amber:charge", - .default_trigger = "sharpsl-charge", - .brightness_set = tosaled_amber_set, -}; - -static struct led_classdev tosa_green_led = { - .name = "tosa:green:mail", - .default_trigger = "nand-disk", - .brightness_set = tosaled_green_set, -}; - -#ifdef CONFIG_PM -static int tosaled_suspend(struct platform_device *dev, pm_message_t state) -{ -#ifdef CONFIG_LEDS_TRIGGERS - if (tosa_amber_led.trigger && strcmp(tosa_amber_led.trigger->name, - "sharpsl-charge")) -#endif - led_classdev_suspend(&tosa_amber_led); - led_classdev_suspend(&tosa_green_led); - return 0; -} - -static int tosaled_resume(struct platform_device *dev) -{ - led_classdev_resume(&tosa_amber_led); - led_classdev_resume(&tosa_green_led); - return 0; -} -#else -#define tosaled_suspend NULL -#define tosaled_resume NULL -#endif - -static int tosaled_probe(struct platform_device *pdev) -{ - int ret; - - ret = led_classdev_register(&pdev->dev, &tosa_amber_led); - if (ret < 0) - return ret; - - ret = led_classdev_register(&pdev->dev, &tosa_green_led); - if (ret < 0) - led_classdev_unregister(&tosa_amber_led); - - return ret; -} - -static int tosaled_remove(struct platform_device *pdev) -{ - led_classdev_unregister(&tosa_amber_led); - led_classdev_unregister(&tosa_green_led); - - return 0; -} - -static struct platform_driver tosaled_driver = { - .probe = tosaled_probe, - .remove = tosaled_remove, - .suspend = tosaled_suspend, - .resume = tosaled_resume, - .driver = { - .name = "tosa-led", - }, -}; - -static int __init tosaled_init(void) -{ - return platform_driver_register(&tosaled_driver); -} - -static void __exit tosaled_exit(void) -{ - platform_driver_unregister(&tosaled_driver); -} - -module_init(tosaled_init); -module_exit(tosaled_exit); - -MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>"); -MODULE_DESCRIPTION("Tosa LED driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0c886c8..2566479 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -22,6 +22,22 @@ config MFD_ASIC3 This driver supports the ASIC3 multifunction chip found on many PDAs (mainly iPAQ and HTC based ones) +config HTC_EGPIO + bool "HTC EGPIO support" + depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB + help + This driver supports the CPLD egpio chip present on + several HTC phones. It provides basic support for input + pins, output pins, and irqs. + +config HTC_PASIC3 + tristate "HTC PASIC3 LED/DS1WM chip support" + help + This core driver provides register access for the LED/DS1WM + chips labeled "AIC2" and "AIC3", found on HTC Blueangel and + HTC Magician devices, respectively. Actual functionality is + handled by the leds-pasic3 and ds1wm drivers. + endmenu menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 521cd5c..eef4e26 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -5,6 +5,9 @@ obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o +obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o +obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o + obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c new file mode 100644 index 0000000..8872cc0 --- /dev/null +++ b/drivers/mfd/htc-egpio.c @@ -0,0 +1,440 @@ +/* + * Support for the GPIO/IRQ expander chips present on several HTC phones. + * These are implemented in CPLD chips present on the board. + * + * Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net> + * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> + * + * This file may be distributed under the terms of the GNU GPL license. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/mfd/htc-egpio.h> + +struct egpio_chip { + int reg_start; + int cached_values; + unsigned long is_out; + struct device *dev; + struct gpio_chip chip; +}; + +struct egpio_info { + spinlock_t lock; + + /* iomem info */ + void __iomem *base_addr; + int bus_shift; /* byte shift */ + int reg_shift; /* bit shift */ + int reg_mask; + + /* irq info */ + int ack_register; + int ack_write; + u16 irqs_enabled; + uint irq_start; + int nirqs; + uint chained_irq; + + /* egpio info */ + struct egpio_chip *chip; + int nchips; +}; + +static inline void egpio_writew(u16 value, struct egpio_info *ei, int reg) +{ + writew(value, ei->base_addr + (reg << ei->bus_shift)); +} + +static inline u16 egpio_readw(struct egpio_info *ei, int reg) +{ + return readw(ei->base_addr + (reg << ei->bus_shift)); +} + +/* + * IRQs + */ + +static inline void ack_irqs(struct egpio_info *ei) +{ + egpio_writew(ei->ack_write, ei, ei->ack_register); + pr_debug("EGPIO ack - write %x to base+%x\n", + ei->ack_write, ei->ack_register << ei->bus_shift); +} + +static void egpio_ack(unsigned int irq) +{ +} + +/* There does not appear to be a way to proactively mask interrupts + * on the egpio chip itself. So, we simply ignore interrupts that + * aren't desired. */ +static void egpio_mask(unsigned int irq) +{ + struct egpio_info *ei = get_irq_chip_data(irq); + ei->irqs_enabled &= ~(1 << (irq - ei->irq_start)); + pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled); +} +static void egpio_unmask(unsigned int irq) +{ + struct egpio_info *ei = get_irq_chip_data(irq); + ei->irqs_enabled |= 1 << (irq - ei->irq_start); + pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled); +} + +static struct irq_chip egpio_muxed_chip = { + .name = "htc-egpio", + .ack = egpio_ack, + .mask = egpio_mask, + .unmask = egpio_unmask, +}; + +static void egpio_handler(unsigned int irq, struct irq_desc *desc) +{ + struct egpio_info *ei = get_irq_data(irq); + int irqpin; + + /* Read current pins. */ + unsigned long readval = egpio_readw(ei, ei->ack_register); + pr_debug("IRQ reg: %x\n", (unsigned int)readval); + /* Ack/unmask interrupts. */ + ack_irqs(ei); + /* Process all set pins. */ + readval &= ei->irqs_enabled; + for_each_bit(irqpin, &readval, ei->nirqs) { + /* Run irq handler */ + pr_debug("got IRQ %d\n", irqpin); + irq = ei->irq_start + irqpin; + desc = &irq_desc[irq]; + desc->handle_irq(irq, desc); + } +} + +int htc_egpio_get_wakeup_irq(struct device *dev) +{ + struct egpio_info *ei = dev_get_drvdata(dev); + + /* Read current pins. */ + u16 readval = egpio_readw(ei, ei->ack_register); + /* Ack/unmask interrupts. */ + ack_irqs(ei); + /* Return first set pin. */ + readval &= ei->irqs_enabled; + return ei->irq_start + ffs(readval) - 1; +} +EXPORT_SYMBOL(htc_egpio_get_wakeup_irq); + +static inline int egpio_pos(struct egpio_info *ei, int bit) +{ + return bit >> ei->reg_shift; +} + +static inline int egpio_bit(struct egpio_info *ei, int bit) +{ + return 1 << (bit & ((1 << ei->reg_shift)-1)); +} + +/* + * Input pins + */ + +static int egpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct egpio_chip *egpio; + struct egpio_info *ei; + unsigned bit; + int reg; + int value; + + pr_debug("egpio_get_value(%d)\n", chip->base + offset); + + egpio = container_of(chip, struct egpio_chip, chip); + ei = dev_get_drvdata(egpio->dev); + bit = egpio_bit(ei, offset); + reg = egpio->reg_start + egpio_pos(ei, offset); + + value = egpio_readw(ei, reg); + pr_debug("readw(%p + %x) = %x\n", + ei->base_addr, reg << ei->bus_shift, value); + return value & bit; +} + +static int egpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct egpio_chip *egpio; + + egpio = container_of(chip, struct egpio_chip, chip); + return test_bit(offset, &egpio->is_out) ? -EINVAL : 0; +} + + +/* + * Output pins + */ + +static void egpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + unsigned long flag; + struct egpio_chip *egpio; + struct egpio_info *ei; + unsigned bit; + int pos; + int reg; + int shift; + + pr_debug("egpio_set(%s, %d(%d), %d)\n", + chip->label, offset, offset+chip->base, value); + + egpio = container_of(chip, struct egpio_chip, chip); + ei = dev_get_drvdata(egpio->dev); + bit = egpio_bit(ei, offset); + pos = egpio_pos(ei, offset); + reg = egpio->reg_start + pos; + shift = pos << ei->reg_shift; + + pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear", + reg, (egpio->cached_values >> shift) & ei->reg_mask); + + spin_lock_irqsave(&ei->lock, flag); + if (value) + egpio->cached_values |= (1 << offset); + else + egpio->cached_values &= ~(1 << offset); + egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg); + spin_unlock_irqrestore(&ei->lock, flag); +} + +static int egpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct egpio_chip *egpio; + + egpio = container_of(chip, struct egpio_chip, chip); + if (test_bit(offset, &egpio->is_out)) { + egpio_set(chip, offset, value); + return 0; + } else { + return -EINVAL; + } +} + +static void egpio_write_cache(struct egpio_info *ei) +{ + int i; + struct egpio_chip *egpio; + int shift; + + for (i = 0; i < ei->nchips; i++) { + egpio = &(ei->chip[i]); + if (!egpio->is_out) + continue; + + for (shift = 0; shift < egpio->chip.ngpio; + shift += (1<<ei->reg_shift)) { + + int reg = egpio->reg_start + egpio_pos(ei, shift); + + if (!((egpio->is_out >> shift) & ei->reg_mask)) + continue; + + pr_debug("EGPIO: setting %x to %x, was %x\n", reg, + (egpio->cached_values >> shift) & ei->reg_mask, + egpio_readw(ei, reg)); + + egpio_writew((egpio->cached_values >> shift) + & ei->reg_mask, ei, reg); + } + } +} + + +/* + * Setup + */ + +static int __init egpio_probe(struct platform_device *pdev) +{ + struct htc_egpio_platform_data *pdata = pdev->dev.platform_data; + struct resource *res; + struct egpio_info *ei; + struct gpio_chip *chip; + unsigned int irq, irq_end; + int i; + int ret; + + /* Initialize ei data structure. */ + ei = kzalloc(sizeof(*ei), GFP_KERNEL); + if (!ei) + return -ENOMEM; + + spin_lock_init(&ei->lock); + + /* Find chained irq */ + ret = -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res) + ei->chained_irq = res->start; + + /* Map egpio chip into virtual address space. */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + goto fail; + ei->base_addr = ioremap_nocache(res->start, res->end - res->start); + if (!ei->base_addr) + goto fail; + pr_debug("EGPIO phys=%08x virt=%p\n", res->start, ei->base_addr); + + if ((pdata->bus_width != 16) && (pdata->bus_width != 32)) + goto fail; + ei->bus_shift = fls(pdata->bus_width - 1) - 3; + pr_debug("bus_shift = %d\n", ei->bus_shift); + + if ((pdata->reg_width != 8) && (pdata->reg_width != 16)) + goto fail; + ei->reg_shift = fls(pdata->reg_width - 1); + pr_debug("reg_shift = %d\n", ei->reg_shift); + + ei->reg_mask = (1 << pdata->reg_width) - 1; + + platform_set_drvdata(pdev, ei); + + ei->nchips = pdata->num_chips; + ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL); + if (!ei) { + ret = -ENOMEM; + goto fail; + } + for (i = 0; i < ei->nchips; i++) { + ei->chip[i].reg_start = pdata->chip[i].reg_start; + ei->chip[i].cached_values = pdata->chip[i].initial_values; + ei->chip[i].is_out = pdata->chip[i].direction; + ei->chip[i].dev = &(pdev->dev); + chip = &(ei->chip[i].chip); + chip->label = "htc-egpio"; + chip->get = egpio_get; + chip->set = egpio_set; + chip->direction_input = egpio_direction_input; + chip->direction_output = egpio_direction_output; + chip->base = pdata->chip[i].gpio_base; + chip->ngpio = pdata->chip[i].num_gpios; + + gpiochip_add(chip); + } + + /* Set initial pin values */ + egpio_write_cache(ei); + + ei->irq_start = pdata->irq_base; + ei->nirqs = pdata->num_irqs; + ei->ack_register = pdata->ack_register; + + if (ei->chained_irq) { + /* Setup irq handlers */ + ei->ack_write = 0xFFFF; + if (pdata->invert_acks) + ei->ack_write = 0; + irq_end = ei->irq_start + ei->nirqs; + for (irq = ei->irq_start; irq < irq_end; irq++) { + set_irq_chip(irq, &egpio_muxed_chip); + set_irq_chip_data(irq, ei); + set_irq_handler(irq, handle_simple_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); + set_irq_data(ei->chained_irq, ei); + set_irq_chained_handler(ei->chained_irq, egpio_handler); + ack_irqs(ei); + + device_init_wakeup(&pdev->dev, 1); + } + + return 0; + +fail: + printk(KERN_ERR "EGPIO failed to setup\n"); + kfree(ei); + return ret; +} + +static int __exit egpio_remove(struct platform_device *pdev) +{ + struct egpio_info *ei = platform_get_drvdata(pdev); + unsigned int irq, irq_end; + + if (ei->chained_irq) { + irq_end = ei->irq_start + ei->nirqs; + for (irq = ei->irq_start; irq < irq_end; irq++) { + set_irq_chip(irq, NULL); + set_irq_handler(irq, NULL); + set_irq_flags(irq, 0); + } + set_irq_chained_handler(ei->chained_irq, NULL); + device_init_wakeup(&pdev->dev, 0); + } + iounmap(ei->base_addr); + kfree(ei->chip); + kfree(ei); + + return 0; +} + +#ifdef CONFIG_PM +static int egpio_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct egpio_info *ei = platform_get_drvdata(pdev); + + if (ei->chained_irq && device_may_wakeup(&pdev->dev)) + enable_irq_wake(ei->chained_irq); + return 0; +} + +static int egpio_resume(struct platform_device *pdev) +{ + struct egpio_info *ei = platform_get_drvdata(pdev); + + if (ei->chained_irq && device_may_wakeup(&pdev->dev)) + disable_irq_wake(ei->chained_irq); + + /* Update registers from the cache, in case + the CPLD was powered off during suspend */ + egpio_write_cache(ei); + return 0; +} +#else +#define egpio_suspend NULL +#define egpio_resume NULL +#endif + + +static struct platform_driver egpio_driver = { + .driver = { + .name = "htc-egpio", + }, + .remove = __exit_p(egpio_remove), + .suspend = egpio_suspend, + .resume = egpio_resume, +}; + +static int __init egpio_init(void) +{ + return platform_driver_probe(&egpio_driver, egpio_probe); +} + +static void __exit egpio_exit(void) +{ + platform_driver_unregister(&egpio_driver); +} + +/* start early for dependencies */ +subsys_initcall(egpio_init); +module_exit(egpio_exit) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin O'Connor <kevin@koconnor.net>"); diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c new file mode 100644 index 0000000..af66f4f --- /dev/null +++ b/drivers/mfd/htc-pasic3.c @@ -0,0 +1,265 @@ +/* + * Core driver for HTC PASIC3 LED/DS1WM chip. + * + * Copyright (C) 2006 Philipp Zabel <philipp.zabel@gmail.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; version 2 of the License. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <linux/ds1wm.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/mfd/htc-pasic3.h> + +#include <asm/arch/pxa-regs.h> + +struct pasic3_data { + void __iomem *mapping; + unsigned int bus_shift; + struct platform_device *ds1wm_pdev; + struct platform_device *led_pdev; +}; + +#define REG_ADDR 5 +#define REG_DATA 6 +#define NUM_REGS 7 + +#define READ_MODE 0x80 + +/* + * write to a secondary register on the PASIC3 + */ +void pasic3_write_register(struct device *dev, u32 reg, u8 val) +{ + struct pasic3_data *asic = dev->driver_data; + int bus_shift = asic->bus_shift; + void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); + void __iomem *data = asic->mapping + (REG_DATA << bus_shift); + + __raw_writeb(~READ_MODE & reg, addr); + __raw_writeb(val, data); +} +EXPORT_SYMBOL(pasic3_write_register); /* for leds-pasic3 */ + +/* + * read from a secondary register on the PASIC3 + */ +u8 pasic3_read_register(struct device *dev, u32 reg) +{ + struct pasic3_data *asic = dev->driver_data; + int bus_shift = asic->bus_shift; + void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); + void __iomem *data = asic->mapping + (REG_DATA << bus_shift); + + __raw_writeb(READ_MODE | reg, addr); + return __raw_readb(data); +} +EXPORT_SYMBOL(pasic3_read_register); /* for leds-pasic3 */ + +/* + * LEDs + */ + +static int led_device_add(struct device *pasic3_dev, + const struct pasic3_leds_machinfo *pdata) +{ + struct pasic3_data *asic = pasic3_dev->driver_data; + struct platform_device *pdev; + int ret; + + pdev = platform_device_alloc("pasic3-led", -1); + if (!pdev) { + dev_dbg(pasic3_dev, "failed to allocate LED platform device\n"); + return -ENOMEM; + } + + ret = platform_device_add_data(pdev, pdata, + sizeof(struct pasic3_leds_machinfo)); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add LED platform data\n"); + goto exit_pdev_put; + } + + pdev->dev.parent = pasic3_dev; + ret = platform_device_add(pdev); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add LED platform device\n"); + goto exit_pdev_put; + } + + asic->led_pdev = pdev; + return 0; + +exit_pdev_put: + platform_device_put(pdev); + return ret; +} + +/* + * DS1WM + */ + +static void ds1wm_enable(struct platform_device *pdev) +{ + struct device *dev = pdev->dev.parent; + int c; + + c = pasic3_read_register(dev, 0x28); + pasic3_write_register(dev, 0x28, c & 0x7f); + + dev_dbg(dev, "DS1WM OWM_EN low (active) %02x\n", c & 0x7f); +} + +static void ds1wm_disable(struct platform_device *pdev) +{ + struct device *dev = pdev->dev.parent; + int c; + + c = pasic3_read_register(dev, 0x28); + pasic3_write_register(dev, 0x28, c | 0x80); + + dev_dbg(dev, "DS1WM OWM_EN high (inactive) %02x\n", c | 0x80); +} + +static struct ds1wm_platform_data ds1wm_pdata = { + .bus_shift = 2, + .enable = ds1wm_enable, + .disable = ds1wm_disable, +}; + +static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift) +{ + struct pasic3_data *asic = pasic3_dev->driver_data; + struct platform_device *pdev; + int ret; + + pdev = platform_device_alloc("ds1wm", -1); + if (!pdev) { + dev_dbg(pasic3_dev, "failed to allocate DS1WM platform device\n"); + return -ENOMEM; + } + + ret = platform_device_add_resources(pdev, pdev->resource, + pdev->num_resources); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add DS1WM resources\n"); + goto exit_pdev_put; + } + + ds1wm_pdata.bus_shift = asic->bus_shift; + ret = platform_device_add_data(pdev, &ds1wm_pdata, + sizeof(struct ds1wm_platform_data)); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add DS1WM platform data\n"); + goto exit_pdev_put; + } + + pdev->dev.parent = pasic3_dev; + ret = platform_device_add(pdev); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add DS1WM platform device\n"); + goto exit_pdev_put; + } + + asic->ds1wm_pdev = pdev; + return 0; + +exit_pdev_put: + platform_device_put(pdev); + return ret; +} + +static int __init pasic3_probe(struct platform_device *pdev) +{ + struct pasic3_platform_data *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct pasic3_data *asic; + struct resource *r; + int ret; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + return -ENXIO; + + if (!request_mem_region(r->start, r->end - r->start + 1, "pasic3")) + return -EBUSY; + + asic = kzalloc(sizeof(struct pasic3_data), GFP_KERNEL); + if (!asic) + return -ENOMEM; + + platform_set_drvdata(pdev, asic); + + if (pdata && pdata->bus_shift) + asic->bus_shift = pdata->bus_shift; + else + asic->bus_shift = 2; + + asic->mapping = ioremap(r->start, r->end - r->start + 1); + if (!asic->mapping) { + dev_err(dev, "couldn't ioremap PASIC3\n"); + kfree(asic); + return -ENOMEM; + } + + ret = ds1wm_device_add(dev, asic->bus_shift); + if (ret < 0) + dev_warn(dev, "failed to register DS1WM\n"); + + if (pdata->led_pdata) { + ret = led_device_add(dev, pdata->led_pdata); + if (ret < 0) + dev_warn(dev, "failed to register LED device\n"); + } + + return 0; +} + +static int pasic3_remove(struct platform_device *pdev) +{ + struct pasic3_data *asic = platform_get_drvdata(pdev); + struct resource *r; + + if (asic->led_pdev) + platform_device_unregister(asic->led_pdev); + if (asic->ds1wm_pdev) + platform_device_unregister(asic->ds1wm_pdev); + + iounmap(asic->mapping); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(r->start, r->end - r->start + 1); + kfree(asic); + return 0; +} + +static struct platform_driver pasic3_driver = { + .driver = { + .name = "pasic3", + }, + .remove = pasic3_remove, +}; + +static int __init pasic3_base_init(void) +{ + return platform_driver_probe(&pasic3_driver, pasic3_probe); +} + +static void __exit pasic3_base_exit(void) +{ + platform_driver_unregister(&pasic3_driver); +} + +module_init(pasic3_base_init); +module_exit(pasic3_base_exit); + +MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); +MODULE_DESCRIPTION("Core driver for HTC PASIC3"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 0ae0d83..978e20a 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -1043,7 +1043,9 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add } else if (machine_is_csb337()) { /* mix link activity status into LED2 link state */ write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22); - } + } else if (machine_is_ecbat91()) + write_phy(phy_address, MII_LEDCTRL_REG, 0x156A); + disable_mdi(); spin_unlock_irq(&lp->lock); diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 8c09344..8db71ab 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -36,6 +36,7 @@ #include <asm/hardware.h> #include <asm/arch/irda.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #ifdef CONFIG_MACH_MAINSTONE #include <asm/arch/mainstone.h> @@ -831,6 +832,11 @@ static int pxa_irda_probe(struct platform_device *pdev) if (err) goto err_mem_5; + if (si->pdata->startup) + err = si->pdata->startup(si->dev); + if (err) + goto err_startup; + dev->hard_start_xmit = pxa_irda_hard_xmit; dev->open = pxa_irda_start; dev->stop = pxa_irda_stop; @@ -856,6 +862,9 @@ static int pxa_irda_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, dev); if (err) { + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); +err_startup: kfree(si->tx_buff.head); err_mem_5: kfree(si->rx_buff.head); @@ -881,6 +890,8 @@ static int pxa_irda_remove(struct platform_device *_dev) if (dev) { struct pxa_irda *si = netdev_priv(dev); unregister_netdev(dev); + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); kfree(si->tx_buff.head); kfree(si->rx_buff.head); clk_put(si->fir_clk); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 125e7b7..f7cb8e0 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -486,12 +486,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) break; case PCI_CLASS_BRIDGE_PCI: - /* don't size subtractive decoding (transparent) - * PCI-to-PCI bridges */ - if (bus->self->transparent) - break; pci_bridge_check_ranges(bus); - /* fall through */ default: pbus_size_io(bus); /* If the bridge supports prefetchable range, size it diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 8b22281..ed8c069 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -200,6 +200,7 @@ config PCMCIA_AU1X00 config PCMCIA_SA1100 tristate "SA1100 support" depends on ARM && ARCH_SA1100 && PCMCIA + depends on ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL || MACH_ARMCORE help Say Y here to include support for SA11x0-based PCMCIA or CF sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/ diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c index fbf2f3a..e7ab060 100644 --- a/drivers/pcmcia/pxa2xx_cm_x270.c +++ b/drivers/pcmcia/pxa2xx_cm_x270.c @@ -20,6 +20,7 @@ #include <asm/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #include <asm/arch/cm-x270.h> #include "soc_common.h" diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 56af1f5..cf29a2d 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -166,15 +166,6 @@ #define SERIAL_IMX_MAJOR 204 #define MINOR_START 41 -#define NR_PORTS 2 - -#define IMX_ISR_PASS_LIMIT 256 - -/* - * This is the size of our serial port register set. - */ -#define UART_PORT_SIZE 0x100 - /* * This determines how often we check the modem status signals * for any change. They generally aren't connected to an IRQ @@ -358,66 +349,60 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) struct tty_struct *tty = sport->port.info->tty; unsigned long flags, temp; - rx = readl(sport->port.membase + URXD0); spin_lock_irqsave(&sport->port.lock,flags); - do { + while (readl(sport->port.membase + USR2) & USR2_RDR) { flg = TTY_NORMAL; sport->port.icount.rx++; + rx = readl(sport->port.membase + URXD0); + temp = readl(sport->port.membase + USR2); - if( temp & USR2_BRCD ) { + if (temp & USR2_BRCD) { writel(temp | USR2_BRCD, sport->port.membase + USR2); - if(uart_handle_break(&sport->port)) - goto ignore_char; + if (uart_handle_break(&sport->port)) + continue; } if (uart_handle_sysrq_char (&sport->port, (unsigned char)rx)) - goto ignore_char; + continue; + + if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { + if (rx & URXD_PRERR) + sport->port.icount.parity++; + else if (rx & URXD_FRMERR) + sport->port.icount.frame++; + if (rx & URXD_OVRRUN) + sport->port.icount.overrun++; + + if (rx & sport->port.ignore_status_mask) { + if (++ignored > 100) + goto out; + continue; + } + + rx &= sport->port.read_status_mask; + + if (rx & URXD_PRERR) + flg = TTY_PARITY; + else if (rx & URXD_FRMERR) + flg = TTY_FRAME; + if (rx & URXD_OVRRUN) + flg = TTY_OVERRUN; - if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) - goto handle_error; +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + } - error_return: tty_insert_flip_char(tty, rx, flg); - - ignore_char: - rx = readl(sport->port.membase + URXD0); - } while(rx & URXD_CHARRDY); + } out: spin_unlock_irqrestore(&sport->port.lock,flags); tty_flip_buffer_push(tty); return IRQ_HANDLED; - -handle_error: - if (rx & URXD_PRERR) - sport->port.icount.parity++; - else if (rx & URXD_FRMERR) - sport->port.icount.frame++; - if (rx & URXD_OVRRUN) - sport->port.icount.overrun++; - - if (rx & sport->port.ignore_status_mask) { - if (++ignored > 100) - goto out; - goto ignore_char; - } - - rx &= sport->port.read_status_mask; - - if (rx & URXD_PRERR) - flg = TTY_PARITY; - else if (rx & URXD_FRMERR) - flg = TTY_FRAME; - if (rx & URXD_OVRRUN) - flg = TTY_OVERRUN; - -#ifdef SUPPORT_SYSRQ - sport->port.sysrq = 0; -#endif - goto error_return; } /* @@ -546,7 +531,7 @@ static int imx_startup(struct uart_port *port) writel(USR1_RTSD, sport->port.membase + USR1); temp = readl(sport->port.membase + UCR1); - temp |= (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; writel(temp, sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR2); @@ -731,9 +716,11 @@ static const char *imx_type(struct uart_port *port) */ static void imx_release_port(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *mmres; - release_mem_region(sport->port.mapbase, UART_PORT_SIZE); + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mmres->start, mmres->end - mmres->start + 1); } /* @@ -741,10 +728,18 @@ static void imx_release_port(struct uart_port *port) */ static int imx_request_port(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *mmres; + void *ret; + + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mmres) + return -ENODEV; + + ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1, + "imx-uart"); - return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, - "imx-uart") != NULL ? 0 : -EBUSY; + return ret ? 0 : -EBUSY; } /* @@ -815,7 +810,7 @@ static struct imx_port imx_ports[] = { .type = PORT_IMX, .iotype = UPIO_MEM, .membase = (void *)IMX_UART1_BASE, - .mapbase = IMX_UART1_BASE, /* FIXME */ + .mapbase = 0x00206000, .irq = UART1_MINT_RX, .uartclk = 16000000, .fifosize = 32, @@ -831,7 +826,7 @@ static struct imx_port imx_ports[] = { .type = PORT_IMX, .iotype = UPIO_MEM, .membase = (void *)IMX_UART2_BASE, - .mapbase = IMX_UART2_BASE, /* FIXME */ + .mapbase = 0x00207000, .irq = UART2_MINT_RX, .uartclk = 16000000, .fifosize = 32, diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 97facb1..7576519 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -45,6 +45,7 @@ #include <asm/irq.h> #include <asm/div64.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #include <asm/arch/bitfield.h> #include <asm/arch/pxafb.h> |