diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/amba/bus.c | 47 | ||||
-rw-r--r-- | drivers/clocksource/Kconfig | 7 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-sa1100.c | 199 |
4 files changed, 253 insertions, 2 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 52ddd9f..f009936 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -18,6 +18,7 @@ #include <linux/pm_domain.h> #include <linux/amba/bus.h> #include <linux/sizes.h> +#include <linux/limits.h> #include <asm/irq.h> @@ -43,6 +44,10 @@ static int amba_match(struct device *dev, struct device_driver *drv) struct amba_device *pcdev = to_amba_device(dev); struct amba_driver *pcdrv = to_amba_driver(drv); + /* When driver_override is set, only bind to the matching driver */ + if (pcdev->driver_override) + return !strcmp(pcdev->driver_override, drv->name); + return amba_lookup(pcdrv->id_table, pcdev) != NULL; } @@ -59,6 +64,47 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } +static ssize_t driver_override_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ + struct amba_device *dev = to_amba_device(_dev); + + if (!dev->driver_override) + return 0; + + return sprintf(buf, "%s\n", dev->driver_override); +} + +static ssize_t driver_override_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct amba_device *dev = to_amba_device(_dev); + char *driver_override, *old = dev->driver_override, *cp; + + if (count > PATH_MAX) + return -EINVAL; + + driver_override = kstrndup(buf, count, GFP_KERNEL); + if (!driver_override) + return -ENOMEM; + + cp = strchr(driver_override, '\n'); + if (cp) + *cp = '\0'; + + if (strlen(driver_override)) { + dev->driver_override = driver_override; + } else { + kfree(driver_override); + dev->driver_override = NULL; + } + + kfree(old); + + return count; +} + #define amba_attr_func(name,fmt,arg...) \ static ssize_t name##_show(struct device *_dev, \ struct device_attribute *attr, char *buf) \ @@ -81,6 +127,7 @@ amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n", static struct device_attribute amba_dev_attrs[] = { __ATTR_RO(id), __ATTR_RO(resource), + __ATTR_RW(driver_override), __ATTR_NULL, }; diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index fc01ec2..8a1479f 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -229,4 +229,11 @@ config CLKSRC_MIPS_GIC depends on MIPS_GIC select CLKSRC_OF +config CLKSRC_PXA + def_bool y if ARCH_PXA || ARCH_SA1100 + select CLKSRC_OF if USE_OF + help + This enables OST0 support available on PXA and SA-11x0 + platforms. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 94d90b2..aa526f4 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o obj-$(CONFIG_ARCH_MARCO) += timer-marco.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o -obj-$(CONFIG_ARCH_PXA) += pxa_timer.o +obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index a90be34..bec397a 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/io.h> +#include <linux/syscore_ops.h> #include <mach/hardware.h> #include <mach/irqs.h> @@ -50,7 +51,7 @@ static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset) { - return offset < 11 ? (IRQ_GPIO0 + offset) : (IRQ_GPIO11 - 11 + offset); + return IRQ_GPIO0 + offset; } static struct gpio_chip sa1100_gpio_chip = { @@ -64,7 +65,203 @@ static struct gpio_chip sa1100_gpio_chip = { .ngpio = GPIO_MAX + 1, }; +/* + * SA1100 GPIO edge detection for IRQs: + * IRQs are generated on Falling-Edge, Rising-Edge, or both. + * Use this instead of directly setting GRER/GFER. + */ +static int GPIO_IRQ_rising_edge; +static int GPIO_IRQ_falling_edge; +static int GPIO_IRQ_mask; + +static int sa1100_gpio_type(struct irq_data *d, unsigned int type) +{ + unsigned int mask; + + mask = BIT(d->hwirq); + + if (type == IRQ_TYPE_PROBE) { + if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask) + return 0; + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + + if (type & IRQ_TYPE_EDGE_RISING) + GPIO_IRQ_rising_edge |= mask; + else + GPIO_IRQ_rising_edge &= ~mask; + if (type & IRQ_TYPE_EDGE_FALLING) + GPIO_IRQ_falling_edge |= mask; + else + GPIO_IRQ_falling_edge &= ~mask; + + GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; + GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; + + return 0; +} + +/* + * GPIO IRQs must be acknowledged. + */ +static void sa1100_gpio_ack(struct irq_data *d) +{ + GEDR = BIT(d->hwirq); +} + +static void sa1100_gpio_mask(struct irq_data *d) +{ + unsigned int mask = BIT(d->hwirq); + + GPIO_IRQ_mask &= ~mask; + + GRER &= ~mask; + GFER &= ~mask; +} + +static void sa1100_gpio_unmask(struct irq_data *d) +{ + unsigned int mask = BIT(d->hwirq); + + GPIO_IRQ_mask |= mask; + + GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; + GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; +} + +static int sa1100_gpio_wake(struct irq_data *d, unsigned int on) +{ + if (on) + PWER |= BIT(d->hwirq); + else + PWER &= ~BIT(d->hwirq); + return 0; +} + +/* + * This is for GPIO IRQs + */ +static struct irq_chip sa1100_gpio_irq_chip = { + .name = "GPIO", + .irq_ack = sa1100_gpio_ack, + .irq_mask = sa1100_gpio_mask, + .irq_unmask = sa1100_gpio_unmask, + .irq_set_type = sa1100_gpio_type, + .irq_set_wake = sa1100_gpio_wake, +}; + +static int sa1100_gpio_irqdomain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + + return 0; +} + +static struct irq_domain_ops sa1100_gpio_irqdomain_ops = { + .map = sa1100_gpio_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, +}; + +static struct irq_domain *sa1100_gpio_irqdomain; + +/* + * IRQ 0-11 (GPIO) handler. We enter here with the + * irq_controller_lock held, and IRQs disabled. Decode the IRQ + * and call the handler. + */ +static void +sa1100_gpio_handler(unsigned int irq, struct irq_desc *desc) +{ + unsigned int mask; + + mask = GEDR; + do { + /* + * clear down all currently active IRQ sources. + * We will be processing them all. + */ + GEDR = mask; + + irq = IRQ_GPIO0; + do { + if (mask & 1) + generic_handle_irq(irq); + mask >>= 1; + irq++; + } while (mask); + + mask = GEDR; + } while (mask); +} + +static int sa1100_gpio_suspend(void) +{ + /* + * Set the appropriate edges for wakeup. + */ + GRER = PWER & GPIO_IRQ_rising_edge; + GFER = PWER & GPIO_IRQ_falling_edge; + + /* + * Clear any pending GPIO interrupts. + */ + GEDR = GEDR; + + return 0; +} + +static void sa1100_gpio_resume(void) +{ + GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; + GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; +} + +static struct syscore_ops sa1100_gpio_syscore_ops = { + .suspend = sa1100_gpio_suspend, + .resume = sa1100_gpio_resume, +}; + +static int __init sa1100_gpio_init_devicefs(void) +{ + register_syscore_ops(&sa1100_gpio_syscore_ops); + return 0; +} + +device_initcall(sa1100_gpio_init_devicefs); + void __init sa1100_init_gpio(void) { + /* clear all GPIO edge detects */ + GFER = 0; + GRER = 0; + GEDR = -1; + gpiochip_add(&sa1100_gpio_chip); + + sa1100_gpio_irqdomain = irq_domain_add_simple(NULL, + 28, IRQ_GPIO0, + &sa1100_gpio_irqdomain_ops, NULL); + + /* + * Install handlers for GPIO 0-10 edge detect interrupts + */ + irq_set_chained_handler(IRQ_GPIO0_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO1_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO2_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO3_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO4_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO5_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO6_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO7_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO8_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO9_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO10_SC, sa1100_gpio_handler); + /* + * Install handler for GPIO 11-27 edge detect interrupts + */ + irq_set_chained_handler(IRQ_GPIO11_27, sa1100_gpio_handler); + } |