| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 1 | /* | 
|  | 2 | * arch/arm/mach-ep93xx/core.c | 
|  | 3 | * Core routines for Cirrus EP93xx chips. | 
|  | 4 | * | 
|  | 5 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 6 | * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org> | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 7 | * | 
|  | 8 | * Thanks go to Michael Burian and Ray Lehtiniemi for their key | 
|  | 9 | * role in the ep93xx linux community. | 
|  | 10 | * | 
|  | 11 | * This program is free software; you can redistribute it and/or modify | 
|  | 12 | * it under the terms of the GNU General Public License as published by | 
|  | 13 | * the Free Software Foundation; either version 2 of the License, or (at | 
|  | 14 | * your option) any later version. | 
|  | 15 | */ | 
|  | 16 |  | 
| Hartley Sweeten | 64d6882 | 2010-01-11 19:33:16 +0100 | [diff] [blame] | 17 | #define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt | 
|  | 18 |  | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 19 | #include <linux/kernel.h> | 
|  | 20 | #include <linux/init.h> | 
| Hartley Sweeten | 583ddaf | 2009-07-06 17:39:50 +0100 | [diff] [blame] | 21 | #include <linux/platform_device.h> | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 22 | #include <linux/interrupt.h> | 
| Matthias Kaehlcke | 63890a0 | 2008-10-29 14:14:52 -0700 | [diff] [blame] | 23 | #include <linux/dma-mapping.h> | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 24 | #include <linux/timex.h> | 
| Hartley Sweeten | 583ddaf | 2009-07-06 17:39:50 +0100 | [diff] [blame] | 25 | #include <linux/io.h> | 
|  | 26 | #include <linux/gpio.h> | 
| Hartley Sweeten | 3aa7a9a | 2009-07-20 18:22:36 +0100 | [diff] [blame] | 27 | #include <linux/leds.h> | 
| Lennert Buytenhek | aee85fe | 2006-03-26 23:16:39 +0100 | [diff] [blame] | 28 | #include <linux/termios.h> | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 29 | #include <linux/amba/bus.h> | 
| Lennert Buytenhek | aee85fe | 2006-03-26 23:16:39 +0100 | [diff] [blame] | 30 | #include <linux/amba/serial.h> | 
| Hartley Sweeten | d52a26a | 2008-10-16 23:57:03 +0100 | [diff] [blame] | 31 | #include <linux/i2c.h> | 
|  | 32 | #include <linux/i2c-gpio.h> | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 33 |  | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 34 | #include <mach/hardware.h> | 
| Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 35 | #include <mach/fb.h> | 
| Hartley Sweeten | 12f56c6 | 2009-10-28 21:04:46 +0100 | [diff] [blame] | 36 | #include <mach/ep93xx_keypad.h> | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 37 |  | 
|  | 38 | #include <asm/mach/map.h> | 
|  | 39 | #include <asm/mach/time.h> | 
|  | 40 | #include <asm/mach/irq.h> | 
|  | 41 |  | 
|  | 42 | #include <asm/hardware/vic.h> | 
|  | 43 |  | 
|  | 44 |  | 
|  | 45 | /************************************************************************* | 
|  | 46 | * Static I/O mappings that are needed for all EP93xx platforms | 
|  | 47 | *************************************************************************/ | 
|  | 48 | static struct map_desc ep93xx_io_desc[] __initdata = { | 
|  | 49 | { | 
|  | 50 | .virtual	= EP93XX_AHB_VIRT_BASE, | 
|  | 51 | .pfn		= __phys_to_pfn(EP93XX_AHB_PHYS_BASE), | 
|  | 52 | .length		= EP93XX_AHB_SIZE, | 
|  | 53 | .type		= MT_DEVICE, | 
|  | 54 | }, { | 
|  | 55 | .virtual	= EP93XX_APB_VIRT_BASE, | 
|  | 56 | .pfn		= __phys_to_pfn(EP93XX_APB_PHYS_BASE), | 
|  | 57 | .length		= EP93XX_APB_SIZE, | 
|  | 58 | .type		= MT_DEVICE, | 
|  | 59 | }, | 
|  | 60 | }; | 
|  | 61 |  | 
|  | 62 | void __init ep93xx_map_io(void) | 
|  | 63 | { | 
|  | 64 | iotable_init(ep93xx_io_desc, ARRAY_SIZE(ep93xx_io_desc)); | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 |  | 
|  | 68 | /************************************************************************* | 
|  | 69 | * Timer handling for EP93xx | 
|  | 70 | ************************************************************************* | 
|  | 71 | * The ep93xx has four internal timers.  Timers 1, 2 (both 16 bit) and | 
|  | 72 | * 3 (32 bit) count down at 508 kHz, are self-reloading, and can generate | 
|  | 73 | * an interrupt on underflow.  Timer 4 (40 bit) counts down at 983.04 kHz, | 
|  | 74 | * is free-running, and can't generate interrupts. | 
|  | 75 | * | 
|  | 76 | * The 508 kHz timers are ideal for use for the timer interrupt, as the | 
|  | 77 | * most common values of HZ divide 508 kHz nicely.  We pick one of the 16 | 
|  | 78 | * bit timers (timer 1) since we don't need more than 16 bits of reload | 
|  | 79 | * value as long as HZ >= 8. | 
|  | 80 | * | 
|  | 81 | * The higher clock rate of timer 4 makes it a better choice than the | 
|  | 82 | * other timers for use in gettimeoffset(), while the fact that it can't | 
|  | 83 | * generate interrupts means we don't have to worry about not being able | 
|  | 84 | * to use this timer for something else.  We also use timer 4 for keeping | 
|  | 85 | * track of lost jiffies. | 
|  | 86 | */ | 
|  | 87 | static unsigned int last_jiffy_time; | 
|  | 88 |  | 
| Julia Lawall | af1057a | 2009-08-03 11:57:20 +0100 | [diff] [blame] | 89 | #define TIMER4_TICKS_PER_JIFFY		DIV_ROUND_CLOSEST(CLOCK_TICK_RATE, HZ) | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 90 |  | 
| Hartley Sweeten | d5565f7 | 2009-04-14 21:38:07 +0100 | [diff] [blame] | 91 | static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id) | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 92 | { | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 93 | __raw_writel(1, EP93XX_TIMER1_CLEAR); | 
| Lennert Buytenhek | f869afa | 2006-06-22 10:30:53 +0100 | [diff] [blame] | 94 | while ((signed long) | 
|  | 95 | (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time) | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 96 | >= TIMER4_TICKS_PER_JIFFY) { | 
|  | 97 | last_jiffy_time += TIMER4_TICKS_PER_JIFFY; | 
| Linus Torvalds | 0cd61b6 | 2006-10-06 10:53:39 -0700 | [diff] [blame] | 98 | timer_tick(); | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 99 | } | 
|  | 100 |  | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 101 | return IRQ_HANDLED; | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | static struct irqaction ep93xx_timer_irq = { | 
|  | 105 | .name		= "ep93xx timer", | 
| Bernhard Walle | b30faba | 2007-05-08 00:35:39 -0700 | [diff] [blame] | 106 | .flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 107 | .handler	= ep93xx_timer_interrupt, | 
|  | 108 | }; | 
|  | 109 |  | 
|  | 110 | static void __init ep93xx_timer_init(void) | 
|  | 111 | { | 
|  | 112 | /* Enable periodic HZ timer.  */ | 
|  | 113 | __raw_writel(0x48, EP93XX_TIMER1_CONTROL); | 
| Lennert Buytenhek | a059e33 | 2006-06-22 10:30:54 +0100 | [diff] [blame] | 114 | __raw_writel((508469 / HZ) - 1, EP93XX_TIMER1_LOAD); | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 115 | __raw_writel(0xc8, EP93XX_TIMER1_CONTROL); | 
|  | 116 |  | 
|  | 117 | /* Enable lost jiffy timer.  */ | 
|  | 118 | __raw_writel(0x100, EP93XX_TIMER4_VALUE_HIGH); | 
|  | 119 |  | 
|  | 120 | setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq); | 
|  | 121 | } | 
|  | 122 |  | 
|  | 123 | static unsigned long ep93xx_gettimeoffset(void) | 
|  | 124 | { | 
|  | 125 | int offset; | 
|  | 126 |  | 
|  | 127 | offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time; | 
|  | 128 |  | 
|  | 129 | /* Calculate (1000000 / 983040) * offset.  */ | 
|  | 130 | return offset + (53 * offset / 3072); | 
|  | 131 | } | 
|  | 132 |  | 
|  | 133 | struct sys_timer ep93xx_timer = { | 
|  | 134 | .init		= ep93xx_timer_init, | 
|  | 135 | .offset		= ep93xx_gettimeoffset, | 
|  | 136 | }; | 
|  | 137 |  | 
|  | 138 |  | 
|  | 139 | /************************************************************************* | 
| Lennert Buytenhek | a8e1966 | 2006-03-20 17:10:14 +0000 | [diff] [blame] | 140 | * GPIO handling for EP93xx | 
|  | 141 | *************************************************************************/ | 
| Lennert Buytenhek | 271f5ca | 2007-02-08 01:01:41 +0100 | [diff] [blame] | 142 | static unsigned char gpio_int_unmasked[3]; | 
|  | 143 | static unsigned char gpio_int_enabled[3]; | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 144 | static unsigned char gpio_int_type1[3]; | 
|  | 145 | static unsigned char gpio_int_type2[3]; | 
| Hartley Sweeten | 68ee3d8 | 2009-05-28 19:58:24 +0100 | [diff] [blame] | 146 | static unsigned char gpio_int_debounce[3]; | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 147 |  | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 148 | /* Port ordering is: A B F */ | 
|  | 149 | static const u8 int_type1_register_offset[3]	= { 0x90, 0xac, 0x4c }; | 
|  | 150 | static const u8 int_type2_register_offset[3]	= { 0x94, 0xb0, 0x50 }; | 
|  | 151 | static const u8 eoi_register_offset[3]		= { 0x98, 0xb4, 0x54 }; | 
| Hartley Sweeten | f69162a | 2008-09-05 17:14:35 +0100 | [diff] [blame] | 152 | static const u8 int_en_register_offset[3]	= { 0x9c, 0xb8, 0x58 }; | 
| Hartley Sweeten | 799a0600 | 2008-10-28 17:55:30 +0100 | [diff] [blame] | 153 | static const u8 int_debounce_register_offset[3]	= { 0xa8, 0xc4, 0x64 }; | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 154 |  | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 155 | void ep93xx_gpio_update_int_params(unsigned port) | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 156 | { | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 157 | BUG_ON(port > 2); | 
|  | 158 |  | 
|  | 159 | __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port])); | 
|  | 160 |  | 
|  | 161 | __raw_writeb(gpio_int_type2[port], | 
|  | 162 | EP93XX_GPIO_REG(int_type2_register_offset[port])); | 
|  | 163 |  | 
|  | 164 | __raw_writeb(gpio_int_type1[port], | 
|  | 165 | EP93XX_GPIO_REG(int_type1_register_offset[port])); | 
|  | 166 |  | 
|  | 167 | __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], | 
|  | 168 | EP93XX_GPIO_REG(int_en_register_offset[port])); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 169 | } | 
|  | 170 |  | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 171 | void ep93xx_gpio_int_mask(unsigned line) | 
| Lennert Buytenhek | a8e1966 | 2006-03-20 17:10:14 +0000 | [diff] [blame] | 172 | { | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 173 | gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7)); | 
| Lennert Buytenhek | a8e1966 | 2006-03-20 17:10:14 +0000 | [diff] [blame] | 174 | } | 
| Lennert Buytenhek | a8e1966 | 2006-03-20 17:10:14 +0000 | [diff] [blame] | 175 |  | 
| Hartley Sweeten | 799a0600 | 2008-10-28 17:55:30 +0100 | [diff] [blame] | 176 | void ep93xx_gpio_int_debounce(unsigned int irq, int enable) | 
|  | 177 | { | 
|  | 178 | int line = irq_to_gpio(irq); | 
|  | 179 | int port = line >> 3; | 
|  | 180 | int port_mask = 1 << (line & 7); | 
|  | 181 |  | 
|  | 182 | if (enable) | 
| Hartley Sweeten | 68ee3d8 | 2009-05-28 19:58:24 +0100 | [diff] [blame] | 183 | gpio_int_debounce[port] |= port_mask; | 
| Hartley Sweeten | 799a0600 | 2008-10-28 17:55:30 +0100 | [diff] [blame] | 184 | else | 
| Hartley Sweeten | 68ee3d8 | 2009-05-28 19:58:24 +0100 | [diff] [blame] | 185 | gpio_int_debounce[port] &= ~port_mask; | 
| Hartley Sweeten | 799a0600 | 2008-10-28 17:55:30 +0100 | [diff] [blame] | 186 |  | 
| Hartley Sweeten | 68ee3d8 | 2009-05-28 19:58:24 +0100 | [diff] [blame] | 187 | __raw_writeb(gpio_int_debounce[port], | 
| Hartley Sweeten | 799a0600 | 2008-10-28 17:55:30 +0100 | [diff] [blame] | 188 | EP93XX_GPIO_REG(int_debounce_register_offset[port])); | 
|  | 189 | } | 
|  | 190 | EXPORT_SYMBOL(ep93xx_gpio_int_debounce); | 
|  | 191 |  | 
| Lennert Buytenhek | a8e1966 | 2006-03-20 17:10:14 +0000 | [diff] [blame] | 192 | /************************************************************************* | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 193 | * EP93xx IRQ handling | 
|  | 194 | *************************************************************************/ | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 195 | static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 196 | { | 
|  | 197 | unsigned char status; | 
|  | 198 | int i; | 
|  | 199 |  | 
|  | 200 | status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); | 
|  | 201 | for (i = 0; i < 8; i++) { | 
|  | 202 | if (status & (1 << i)) { | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 203 | int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; | 
| Dmitry Baryshkov | d8aa025 | 2008-10-09 13:36:24 +0100 | [diff] [blame] | 204 | generic_handle_irq(gpio_irq); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 205 | } | 
|  | 206 | } | 
|  | 207 |  | 
|  | 208 | status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); | 
|  | 209 | for (i = 0; i < 8; i++) { | 
|  | 210 | if (status & (1 << i)) { | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 211 | int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; | 
| Dmitry Baryshkov | d8aa025 | 2008-10-09 13:36:24 +0100 | [diff] [blame] | 212 | generic_handle_irq(gpio_irq); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 213 | } | 
|  | 214 | } | 
|  | 215 | } | 
|  | 216 |  | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 217 | static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) | 
|  | 218 | { | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 219 | /* | 
|  | 220 | * map discontiguous hw irq range to continous sw irq range: | 
|  | 221 | * | 
|  | 222 | *  IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) | 
|  | 223 | */ | 
|  | 224 | int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ | 
|  | 225 | int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 226 |  | 
| Dmitry Baryshkov | d8aa025 | 2008-10-09 13:36:24 +0100 | [diff] [blame] | 227 | generic_handle_irq(gpio_irq); | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 228 | } | 
|  | 229 |  | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 230 | static void ep93xx_gpio_irq_ack(unsigned int irq) | 
|  | 231 | { | 
|  | 232 | int line = irq_to_gpio(irq); | 
|  | 233 | int port = line >> 3; | 
|  | 234 | int port_mask = 1 << (line & 7); | 
|  | 235 |  | 
| Dmitry Baryshkov | 6cab486 | 2008-07-27 04:23:31 +0100 | [diff] [blame] | 236 | if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 237 | gpio_int_type2[port] ^= port_mask; /* switch edge direction */ | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 238 | ep93xx_gpio_update_int_params(port); | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 239 | } | 
|  | 240 |  | 
|  | 241 | __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); | 
|  | 242 | } | 
|  | 243 |  | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 244 | static void ep93xx_gpio_irq_mask_ack(unsigned int irq) | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 245 | { | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 246 | int line = irq_to_gpio(irq); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 247 | int port = line >> 3; | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 248 | int port_mask = 1 << (line & 7); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 249 |  | 
| Dmitry Baryshkov | 6cab486 | 2008-07-27 04:23:31 +0100 | [diff] [blame] | 250 | if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 251 | gpio_int_type2[port] ^= port_mask; /* switch edge direction */ | 
|  | 252 |  | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 253 | gpio_int_unmasked[port] &= ~port_mask; | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 254 | ep93xx_gpio_update_int_params(port); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 255 |  | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 256 | __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 257 | } | 
|  | 258 |  | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 259 | static void ep93xx_gpio_irq_mask(unsigned int irq) | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 260 | { | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 261 | int line = irq_to_gpio(irq); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 262 | int port = line >> 3; | 
|  | 263 |  | 
| Lennert Buytenhek | 271f5ca | 2007-02-08 01:01:41 +0100 | [diff] [blame] | 264 | gpio_int_unmasked[port] &= ~(1 << (line & 7)); | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 265 | ep93xx_gpio_update_int_params(port); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 266 | } | 
|  | 267 |  | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 268 | static void ep93xx_gpio_irq_unmask(unsigned int irq) | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 269 | { | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 270 | int line = irq_to_gpio(irq); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 271 | int port = line >> 3; | 
|  | 272 |  | 
| Lennert Buytenhek | 271f5ca | 2007-02-08 01:01:41 +0100 | [diff] [blame] | 273 | gpio_int_unmasked[port] |= 1 << (line & 7); | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 274 | ep93xx_gpio_update_int_params(port); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 275 | } | 
|  | 276 |  | 
|  | 277 |  | 
|  | 278 | /* | 
|  | 279 | * gpio_int_type1 controls whether the interrupt is level (0) or | 
|  | 280 | * edge (1) triggered, while gpio_int_type2 controls whether it | 
|  | 281 | * triggers on low/falling (0) or high/rising (1). | 
|  | 282 | */ | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 283 | static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 284 | { | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 285 | struct irq_desc *desc = irq_desc + irq; | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 286 | const int gpio = irq_to_gpio(irq); | 
|  | 287 | const int port = gpio >> 3; | 
|  | 288 | const int port_mask = 1 << (gpio & 7); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 289 |  | 
| Ryan Mallon | f8b6389 | 2008-04-28 23:35:47 +0100 | [diff] [blame] | 290 | gpio_direction_input(gpio); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 291 |  | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 292 | switch (type) { | 
| Dmitry Baryshkov | 6cab486 | 2008-07-27 04:23:31 +0100 | [diff] [blame] | 293 | case IRQ_TYPE_EDGE_RISING: | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 294 | gpio_int_type1[port] |= port_mask; | 
|  | 295 | gpio_int_type2[port] |= port_mask; | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 296 | desc->handle_irq = handle_edge_irq; | 
|  | 297 | break; | 
| Dmitry Baryshkov | 6cab486 | 2008-07-27 04:23:31 +0100 | [diff] [blame] | 298 | case IRQ_TYPE_EDGE_FALLING: | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 299 | gpio_int_type1[port] |= port_mask; | 
|  | 300 | gpio_int_type2[port] &= ~port_mask; | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 301 | desc->handle_irq = handle_edge_irq; | 
|  | 302 | break; | 
| Dmitry Baryshkov | 6cab486 | 2008-07-27 04:23:31 +0100 | [diff] [blame] | 303 | case IRQ_TYPE_LEVEL_HIGH: | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 304 | gpio_int_type1[port] &= ~port_mask; | 
|  | 305 | gpio_int_type2[port] |= port_mask; | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 306 | desc->handle_irq = handle_level_irq; | 
|  | 307 | break; | 
| Dmitry Baryshkov | 6cab486 | 2008-07-27 04:23:31 +0100 | [diff] [blame] | 308 | case IRQ_TYPE_LEVEL_LOW: | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 309 | gpio_int_type1[port] &= ~port_mask; | 
|  | 310 | gpio_int_type2[port] &= ~port_mask; | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 311 | desc->handle_irq = handle_level_irq; | 
|  | 312 | break; | 
| Dmitry Baryshkov | 6cab486 | 2008-07-27 04:23:31 +0100 | [diff] [blame] | 313 | case IRQ_TYPE_EDGE_BOTH: | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 314 | gpio_int_type1[port] |= port_mask; | 
|  | 315 | /* set initial polarity based on current input level */ | 
|  | 316 | if (gpio_get_value(gpio)) | 
|  | 317 | gpio_int_type2[port] &= ~port_mask; /* falling */ | 
|  | 318 | else | 
|  | 319 | gpio_int_type2[port] |= port_mask; /* rising */ | 
|  | 320 | desc->handle_irq = handle_edge_irq; | 
|  | 321 | break; | 
|  | 322 | default: | 
| Hartley Sweeten | 64d6882 | 2010-01-11 19:33:16 +0100 | [diff] [blame] | 323 | pr_err("failed to set irq type %d for gpio %d\n", type, gpio); | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 324 | return -EINVAL; | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 325 | } | 
|  | 326 |  | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 327 | gpio_int_enabled[port] |= port_mask; | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 328 |  | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 329 | desc->status &= ~IRQ_TYPE_SENSE_MASK; | 
|  | 330 | desc->status |= type & IRQ_TYPE_SENSE_MASK; | 
|  | 331 |  | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 332 | ep93xx_gpio_update_int_params(port); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 333 |  | 
|  | 334 | return 0; | 
|  | 335 | } | 
|  | 336 |  | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 337 | static struct irq_chip ep93xx_gpio_irq_chip = { | 
|  | 338 | .name		= "GPIO", | 
| Herbert Valerio Riedel | 3c9a071 | 2007-11-26 18:49:08 +0100 | [diff] [blame] | 339 | .ack		= ep93xx_gpio_irq_ack, | 
|  | 340 | .mask_ack	= ep93xx_gpio_irq_mask_ack, | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 341 | .mask		= ep93xx_gpio_irq_mask, | 
|  | 342 | .unmask		= ep93xx_gpio_irq_unmask, | 
|  | 343 | .set_type	= ep93xx_gpio_irq_type, | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 344 | }; | 
|  | 345 |  | 
|  | 346 |  | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 347 | void __init ep93xx_init_irq(void) | 
|  | 348 | { | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 349 | int gpio_irq; | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 350 |  | 
| Hartley Sweeten | 5396730 | 2009-07-09 23:22:07 +0100 | [diff] [blame] | 351 | vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0); | 
|  | 352 | vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 353 |  | 
| Herbert Valerio Riedel | 7ca7225 | 2007-11-26 18:45:59 +0100 | [diff] [blame] | 354 | for (gpio_irq = gpio_to_irq(0); | 
|  | 355 | gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { | 
|  | 356 | set_irq_chip(gpio_irq, &ep93xx_gpio_irq_chip); | 
|  | 357 | set_irq_handler(gpio_irq, handle_level_irq); | 
|  | 358 | set_irq_flags(gpio_irq, IRQF_VALID); | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 359 | } | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 360 |  | 
| Lennert Buytenhek | bd20ff5 | 2006-03-20 21:02:37 +0000 | [diff] [blame] | 361 | set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler); | 
| Lennert Buytenhek | 4932e39 | 2007-02-05 00:38:48 +0100 | [diff] [blame] | 362 | set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler); | 
|  | 363 | set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler); | 
|  | 364 | set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler); | 
|  | 365 | set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler); | 
|  | 366 | set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler); | 
|  | 367 | set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler); | 
|  | 368 | set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler); | 
|  | 369 | set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler); | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 370 | } | 
|  | 371 |  | 
|  | 372 |  | 
|  | 373 | /************************************************************************* | 
| Hartley Sweeten | 02239f0 | 2009-07-08 02:00:49 +0100 | [diff] [blame] | 374 | * EP93xx System Controller Software Locked register handling | 
|  | 375 | *************************************************************************/ | 
|  | 376 |  | 
|  | 377 | /* | 
|  | 378 | * syscon_swlock prevents anything else from writing to the syscon | 
|  | 379 | * block while a software locked register is being written. | 
|  | 380 | */ | 
|  | 381 | static DEFINE_SPINLOCK(syscon_swlock); | 
|  | 382 |  | 
| Ryan Mallon | fbeeea5 | 2009-07-15 21:51:59 +0100 | [diff] [blame] | 383 | void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg) | 
| Hartley Sweeten | 02239f0 | 2009-07-08 02:00:49 +0100 | [diff] [blame] | 384 | { | 
|  | 385 | unsigned long flags; | 
|  | 386 |  | 
|  | 387 | spin_lock_irqsave(&syscon_swlock, flags); | 
|  | 388 |  | 
|  | 389 | __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); | 
|  | 390 | __raw_writel(val, reg); | 
|  | 391 |  | 
|  | 392 | spin_unlock_irqrestore(&syscon_swlock, flags); | 
|  | 393 | } | 
|  | 394 | EXPORT_SYMBOL(ep93xx_syscon_swlocked_write); | 
|  | 395 |  | 
|  | 396 | void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits) | 
|  | 397 | { | 
|  | 398 | unsigned long flags; | 
|  | 399 | unsigned int val; | 
|  | 400 |  | 
|  | 401 | spin_lock_irqsave(&syscon_swlock, flags); | 
|  | 402 |  | 
|  | 403 | val = __raw_readl(EP93XX_SYSCON_DEVCFG); | 
|  | 404 | val |= set_bits; | 
|  | 405 | val &= ~clear_bits; | 
|  | 406 | __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); | 
|  | 407 | __raw_writel(val, EP93XX_SYSCON_DEVCFG); | 
|  | 408 |  | 
|  | 409 | spin_unlock_irqrestore(&syscon_swlock, flags); | 
|  | 410 | } | 
|  | 411 | EXPORT_SYMBOL(ep93xx_devcfg_set_clear); | 
|  | 412 |  | 
|  | 413 |  | 
|  | 414 | /************************************************************************* | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 415 | * EP93xx peripheral handling | 
|  | 416 | *************************************************************************/ | 
| Lennert Buytenhek | aee85fe | 2006-03-26 23:16:39 +0100 | [diff] [blame] | 417 | #define EP93XX_UART_MCR_OFFSET		(0x0100) | 
|  | 418 |  | 
|  | 419 | static void ep93xx_uart_set_mctrl(struct amba_device *dev, | 
|  | 420 | void __iomem *base, unsigned int mctrl) | 
|  | 421 | { | 
|  | 422 | unsigned int mcr; | 
|  | 423 |  | 
|  | 424 | mcr = 0; | 
|  | 425 | if (!(mctrl & TIOCM_RTS)) | 
|  | 426 | mcr |= 2; | 
|  | 427 | if (!(mctrl & TIOCM_DTR)) | 
|  | 428 | mcr |= 1; | 
|  | 429 |  | 
|  | 430 | __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET); | 
|  | 431 | } | 
|  | 432 |  | 
|  | 433 | static struct amba_pl010_data ep93xx_uart_data = { | 
|  | 434 | .set_mctrl	= ep93xx_uart_set_mctrl, | 
|  | 435 | }; | 
|  | 436 |  | 
|  | 437 | static struct amba_device uart1_device = { | 
|  | 438 | .dev		= { | 
| Kay Sievers | 1d559e2 | 2009-01-06 10:44:43 -0800 | [diff] [blame] | 439 | .init_name	= "apb:uart1", | 
| Lennert Buytenhek | aee85fe | 2006-03-26 23:16:39 +0100 | [diff] [blame] | 440 | .platform_data	= &ep93xx_uart_data, | 
|  | 441 | }, | 
|  | 442 | .res		= { | 
|  | 443 | .start	= EP93XX_UART1_PHYS_BASE, | 
|  | 444 | .end	= EP93XX_UART1_PHYS_BASE + 0x0fff, | 
|  | 445 | .flags	= IORESOURCE_MEM, | 
|  | 446 | }, | 
|  | 447 | .irq		= { IRQ_EP93XX_UART1, NO_IRQ }, | 
|  | 448 | .periphid	= 0x00041010, | 
|  | 449 | }; | 
|  | 450 |  | 
|  | 451 | static struct amba_device uart2_device = { | 
|  | 452 | .dev		= { | 
| Kay Sievers | 1d559e2 | 2009-01-06 10:44:43 -0800 | [diff] [blame] | 453 | .init_name	= "apb:uart2", | 
| Lennert Buytenhek | aee85fe | 2006-03-26 23:16:39 +0100 | [diff] [blame] | 454 | .platform_data	= &ep93xx_uart_data, | 
|  | 455 | }, | 
|  | 456 | .res		= { | 
|  | 457 | .start	= EP93XX_UART2_PHYS_BASE, | 
|  | 458 | .end	= EP93XX_UART2_PHYS_BASE + 0x0fff, | 
|  | 459 | .flags	= IORESOURCE_MEM, | 
|  | 460 | }, | 
|  | 461 | .irq		= { IRQ_EP93XX_UART2, NO_IRQ }, | 
|  | 462 | .periphid	= 0x00041010, | 
|  | 463 | }; | 
|  | 464 |  | 
|  | 465 | static struct amba_device uart3_device = { | 
|  | 466 | .dev		= { | 
| Kay Sievers | 1d559e2 | 2009-01-06 10:44:43 -0800 | [diff] [blame] | 467 | .init_name	= "apb:uart3", | 
| Lennert Buytenhek | aee85fe | 2006-03-26 23:16:39 +0100 | [diff] [blame] | 468 | .platform_data	= &ep93xx_uart_data, | 
|  | 469 | }, | 
|  | 470 | .res		= { | 
|  | 471 | .start	= EP93XX_UART3_PHYS_BASE, | 
|  | 472 | .end	= EP93XX_UART3_PHYS_BASE + 0x0fff, | 
|  | 473 | .flags	= IORESOURCE_MEM, | 
|  | 474 | }, | 
|  | 475 | .irq		= { IRQ_EP93XX_UART3, NO_IRQ }, | 
|  | 476 | .periphid	= 0x00041010, | 
|  | 477 | }; | 
|  | 478 |  | 
| Lennert Buytenhek | 4165813 | 2006-04-02 16:17:34 +0100 | [diff] [blame] | 479 |  | 
| Hartley Sweeten | 38f7b00 | 2009-04-15 23:18:26 +0100 | [diff] [blame] | 480 | static struct resource ep93xx_rtc_resource[] = { | 
|  | 481 | { | 
|  | 482 | .start		= EP93XX_RTC_PHYS_BASE, | 
|  | 483 | .end		= EP93XX_RTC_PHYS_BASE + 0x10c - 1, | 
|  | 484 | .flags		= IORESOURCE_MEM, | 
|  | 485 | }, | 
|  | 486 | }; | 
|  | 487 |  | 
| Lennert Buytenhek | 4165813 | 2006-04-02 16:17:34 +0100 | [diff] [blame] | 488 | static struct platform_device ep93xx_rtc_device = { | 
| Hartley Sweeten | 38f7b00 | 2009-04-15 23:18:26 +0100 | [diff] [blame] | 489 | .name		= "ep93xx-rtc", | 
|  | 490 | .id		= -1, | 
|  | 491 | .num_resources	= ARRAY_SIZE(ep93xx_rtc_resource), | 
|  | 492 | .resource	= ep93xx_rtc_resource, | 
| Lennert Buytenhek | 4165813 | 2006-04-02 16:17:34 +0100 | [diff] [blame] | 493 | }; | 
|  | 494 |  | 
|  | 495 |  | 
| Lennert Buytenhek | 1f64eb3 | 2006-06-24 10:33:03 +0100 | [diff] [blame] | 496 | static struct resource ep93xx_ohci_resources[] = { | 
|  | 497 | [0] = { | 
|  | 498 | .start	= EP93XX_USB_PHYS_BASE, | 
|  | 499 | .end	= EP93XX_USB_PHYS_BASE + 0x0fff, | 
|  | 500 | .flags	= IORESOURCE_MEM, | 
|  | 501 | }, | 
|  | 502 | [1] = { | 
|  | 503 | .start	= IRQ_EP93XX_USB, | 
|  | 504 | .end	= IRQ_EP93XX_USB, | 
|  | 505 | .flags	= IORESOURCE_IRQ, | 
|  | 506 | }, | 
|  | 507 | }; | 
|  | 508 |  | 
| Matthias Kaehlcke | 63890a0 | 2008-10-29 14:14:52 -0700 | [diff] [blame] | 509 |  | 
| Lennert Buytenhek | 1f64eb3 | 2006-06-24 10:33:03 +0100 | [diff] [blame] | 510 | static struct platform_device ep93xx_ohci_device = { | 
|  | 511 | .name		= "ep93xx-ohci", | 
|  | 512 | .id		= -1, | 
|  | 513 | .dev		= { | 
| Matthias Kaehlcke | 63890a0 | 2008-10-29 14:14:52 -0700 | [diff] [blame] | 514 | .dma_mask		= &ep93xx_ohci_device.dev.coherent_dma_mask, | 
|  | 515 | .coherent_dma_mask	= DMA_BIT_MASK(32), | 
| Lennert Buytenhek | 1f64eb3 | 2006-06-24 10:33:03 +0100 | [diff] [blame] | 516 | }, | 
|  | 517 | .num_resources	= ARRAY_SIZE(ep93xx_ohci_resources), | 
|  | 518 | .resource	= ep93xx_ohci_resources, | 
|  | 519 | }; | 
|  | 520 |  | 
| Hartley Sweeten | a0a08fd | 2008-10-04 20:01:49 +0100 | [diff] [blame] | 521 | static struct ep93xx_eth_data ep93xx_eth_data; | 
|  | 522 |  | 
|  | 523 | static struct resource ep93xx_eth_resource[] = { | 
|  | 524 | { | 
|  | 525 | .start	= EP93XX_ETHERNET_PHYS_BASE, | 
|  | 526 | .end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff, | 
|  | 527 | .flags	= IORESOURCE_MEM, | 
|  | 528 | }, { | 
|  | 529 | .start	= IRQ_EP93XX_ETHERNET, | 
|  | 530 | .end	= IRQ_EP93XX_ETHERNET, | 
|  | 531 | .flags	= IORESOURCE_IRQ, | 
|  | 532 | } | 
|  | 533 | }; | 
|  | 534 |  | 
|  | 535 | static struct platform_device ep93xx_eth_device = { | 
|  | 536 | .name		= "ep93xx-eth", | 
|  | 537 | .id		= -1, | 
|  | 538 | .dev		= { | 
|  | 539 | .platform_data	= &ep93xx_eth_data, | 
|  | 540 | }, | 
|  | 541 | .num_resources	= ARRAY_SIZE(ep93xx_eth_resource), | 
|  | 542 | .resource	= ep93xx_eth_resource, | 
|  | 543 | }; | 
|  | 544 |  | 
|  | 545 | void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr) | 
|  | 546 | { | 
| Hartley Sweeten | 5b1c3c8 | 2009-07-13 19:50:10 +0100 | [diff] [blame] | 547 | if (copy_addr) | 
|  | 548 | memcpy_fromio(data->dev_addr, EP93XX_ETHERNET_BASE + 0x50, 6); | 
| Hartley Sweeten | a0a08fd | 2008-10-04 20:01:49 +0100 | [diff] [blame] | 549 |  | 
|  | 550 | ep93xx_eth_data = *data; | 
|  | 551 | platform_device_register(&ep93xx_eth_device); | 
|  | 552 | } | 
|  | 553 |  | 
| Hartley Sweeten | 6531a99 | 2009-10-08 00:45:00 +0100 | [diff] [blame] | 554 |  | 
|  | 555 | /************************************************************************* | 
|  | 556 | * EP93xx i2c peripheral handling | 
|  | 557 | *************************************************************************/ | 
|  | 558 | static struct i2c_gpio_platform_data ep93xx_i2c_data; | 
| Hartley Sweeten | d52a26a | 2008-10-16 23:57:03 +0100 | [diff] [blame] | 559 |  | 
|  | 560 | static struct platform_device ep93xx_i2c_device = { | 
|  | 561 | .name			= "i2c-gpio", | 
|  | 562 | .id			= 0, | 
|  | 563 | .dev.platform_data	= &ep93xx_i2c_data, | 
|  | 564 | }; | 
|  | 565 |  | 
| Hartley Sweeten | 6531a99 | 2009-10-08 00:45:00 +0100 | [diff] [blame] | 566 | void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data, | 
|  | 567 | struct i2c_board_info *devices, int num) | 
| Hartley Sweeten | d52a26a | 2008-10-16 23:57:03 +0100 | [diff] [blame] | 568 | { | 
| Hartley Sweeten | 6531a99 | 2009-10-08 00:45:00 +0100 | [diff] [blame] | 569 | /* | 
|  | 570 | * Set the EEPROM interface pin drive type control. | 
|  | 571 | * Defines the driver type for the EECLK and EEDAT pins as either | 
|  | 572 | * open drain, which will require an external pull-up, or a normal | 
|  | 573 | * CMOS driver. | 
|  | 574 | */ | 
|  | 575 | if (data->sda_is_open_drain && data->sda_pin != EP93XX_GPIO_LINE_EEDAT) | 
| Hartley Sweeten | 64d6882 | 2010-01-11 19:33:16 +0100 | [diff] [blame] | 576 | pr_warning("sda != EEDAT, open drain has no effect\n"); | 
| Hartley Sweeten | 6531a99 | 2009-10-08 00:45:00 +0100 | [diff] [blame] | 577 | if (data->scl_is_open_drain && data->scl_pin != EP93XX_GPIO_LINE_EECLK) | 
| Hartley Sweeten | 64d6882 | 2010-01-11 19:33:16 +0100 | [diff] [blame] | 578 | pr_warning("scl != EECLK, open drain has no effect\n"); | 
| Hartley Sweeten | 6531a99 | 2009-10-08 00:45:00 +0100 | [diff] [blame] | 579 |  | 
|  | 580 | __raw_writel((data->sda_is_open_drain << 1) | | 
|  | 581 | (data->scl_is_open_drain << 0), | 
|  | 582 | EP93XX_GPIO_EEDRIVE); | 
|  | 583 |  | 
|  | 584 | ep93xx_i2c_data = *data; | 
| Hartley Sweeten | d52a26a | 2008-10-16 23:57:03 +0100 | [diff] [blame] | 585 | i2c_register_board_info(0, devices, num); | 
|  | 586 | platform_device_register(&ep93xx_i2c_device); | 
|  | 587 | } | 
|  | 588 |  | 
| Hartley Sweeten | 3aa7a9a | 2009-07-20 18:22:36 +0100 | [diff] [blame] | 589 |  | 
|  | 590 | /************************************************************************* | 
|  | 591 | * EP93xx LEDs | 
|  | 592 | *************************************************************************/ | 
|  | 593 | static struct gpio_led ep93xx_led_pins[] = { | 
|  | 594 | { | 
|  | 595 | .name			= "platform:grled", | 
|  | 596 | .gpio			= EP93XX_GPIO_LINE_GRLED, | 
|  | 597 | }, { | 
|  | 598 | .name			= "platform:rdled", | 
|  | 599 | .gpio			= EP93XX_GPIO_LINE_RDLED, | 
|  | 600 | }, | 
|  | 601 | }; | 
|  | 602 |  | 
|  | 603 | static struct gpio_led_platform_data ep93xx_led_data = { | 
|  | 604 | .num_leds	= ARRAY_SIZE(ep93xx_led_pins), | 
|  | 605 | .leds		= ep93xx_led_pins, | 
|  | 606 | }; | 
|  | 607 |  | 
|  | 608 | static struct platform_device ep93xx_leds = { | 
|  | 609 | .name		= "leds-gpio", | 
|  | 610 | .id		= -1, | 
|  | 611 | .dev		= { | 
|  | 612 | .platform_data	= &ep93xx_led_data, | 
|  | 613 | }, | 
|  | 614 | }; | 
|  | 615 |  | 
|  | 616 |  | 
| Hartley Sweeten | ef12379 | 2009-07-29 22:41:06 +0100 | [diff] [blame] | 617 | /************************************************************************* | 
|  | 618 | * EP93xx pwm peripheral handling | 
|  | 619 | *************************************************************************/ | 
|  | 620 | static struct resource ep93xx_pwm0_resource[] = { | 
|  | 621 | { | 
|  | 622 | .start	= EP93XX_PWM_PHYS_BASE, | 
|  | 623 | .end	= EP93XX_PWM_PHYS_BASE + 0x10 - 1, | 
|  | 624 | .flags	= IORESOURCE_MEM, | 
|  | 625 | }, | 
|  | 626 | }; | 
|  | 627 |  | 
|  | 628 | static struct platform_device ep93xx_pwm0_device = { | 
|  | 629 | .name		= "ep93xx-pwm", | 
|  | 630 | .id		= 0, | 
|  | 631 | .num_resources	= ARRAY_SIZE(ep93xx_pwm0_resource), | 
|  | 632 | .resource	= ep93xx_pwm0_resource, | 
|  | 633 | }; | 
|  | 634 |  | 
|  | 635 | static struct resource ep93xx_pwm1_resource[] = { | 
|  | 636 | { | 
|  | 637 | .start	= EP93XX_PWM_PHYS_BASE + 0x20, | 
|  | 638 | .end	= EP93XX_PWM_PHYS_BASE + 0x30 - 1, | 
|  | 639 | .flags	= IORESOURCE_MEM, | 
|  | 640 | }, | 
|  | 641 | }; | 
|  | 642 |  | 
|  | 643 | static struct platform_device ep93xx_pwm1_device = { | 
|  | 644 | .name		= "ep93xx-pwm", | 
|  | 645 | .id		= 1, | 
|  | 646 | .num_resources	= ARRAY_SIZE(ep93xx_pwm1_resource), | 
|  | 647 | .resource	= ep93xx_pwm1_resource, | 
|  | 648 | }; | 
|  | 649 |  | 
|  | 650 | void __init ep93xx_register_pwm(int pwm0, int pwm1) | 
|  | 651 | { | 
|  | 652 | if (pwm0) | 
|  | 653 | platform_device_register(&ep93xx_pwm0_device); | 
|  | 654 |  | 
|  | 655 | /* NOTE: EP9307 does not have PWMOUT1 (pin EGPIO14) */ | 
|  | 656 | if (pwm1) | 
|  | 657 | platform_device_register(&ep93xx_pwm1_device); | 
|  | 658 | } | 
|  | 659 |  | 
|  | 660 | int ep93xx_pwm_acquire_gpio(struct platform_device *pdev) | 
|  | 661 | { | 
|  | 662 | int err; | 
|  | 663 |  | 
|  | 664 | if (pdev->id == 0) { | 
|  | 665 | err = 0; | 
|  | 666 | } else if (pdev->id == 1) { | 
|  | 667 | err = gpio_request(EP93XX_GPIO_LINE_EGPIO14, | 
|  | 668 | dev_name(&pdev->dev)); | 
|  | 669 | if (err) | 
|  | 670 | return err; | 
|  | 671 | err = gpio_direction_output(EP93XX_GPIO_LINE_EGPIO14, 0); | 
|  | 672 | if (err) | 
|  | 673 | goto fail; | 
|  | 674 |  | 
|  | 675 | /* PWM 1 output on EGPIO[14] */ | 
|  | 676 | ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_PONG); | 
|  | 677 | } else { | 
|  | 678 | err = -ENODEV; | 
|  | 679 | } | 
|  | 680 |  | 
|  | 681 | return err; | 
|  | 682 |  | 
|  | 683 | fail: | 
|  | 684 | gpio_free(EP93XX_GPIO_LINE_EGPIO14); | 
|  | 685 | return err; | 
|  | 686 | } | 
|  | 687 | EXPORT_SYMBOL(ep93xx_pwm_acquire_gpio); | 
|  | 688 |  | 
|  | 689 | void ep93xx_pwm_release_gpio(struct platform_device *pdev) | 
|  | 690 | { | 
|  | 691 | if (pdev->id == 1) { | 
|  | 692 | gpio_direction_input(EP93XX_GPIO_LINE_EGPIO14); | 
|  | 693 | gpio_free(EP93XX_GPIO_LINE_EGPIO14); | 
|  | 694 |  | 
|  | 695 | /* EGPIO[14] used for GPIO */ | 
|  | 696 | ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_PONG); | 
|  | 697 | } | 
|  | 698 | } | 
|  | 699 | EXPORT_SYMBOL(ep93xx_pwm_release_gpio); | 
|  | 700 |  | 
|  | 701 |  | 
| Ryan Mallon | c601218 | 2009-09-22 16:47:09 -0700 | [diff] [blame] | 702 | /************************************************************************* | 
|  | 703 | * EP93xx video peripheral handling | 
|  | 704 | *************************************************************************/ | 
|  | 705 | static struct ep93xxfb_mach_info ep93xxfb_data; | 
|  | 706 |  | 
|  | 707 | static struct resource ep93xx_fb_resource[] = { | 
|  | 708 | { | 
|  | 709 | .start		= EP93XX_RASTER_PHYS_BASE, | 
|  | 710 | .end		= EP93XX_RASTER_PHYS_BASE + 0x800 - 1, | 
|  | 711 | .flags		= IORESOURCE_MEM, | 
|  | 712 | }, | 
|  | 713 | }; | 
|  | 714 |  | 
|  | 715 | static struct platform_device ep93xx_fb_device = { | 
|  | 716 | .name			= "ep93xx-fb", | 
|  | 717 | .id			= -1, | 
|  | 718 | .dev			= { | 
|  | 719 | .platform_data	= &ep93xxfb_data, | 
|  | 720 | .coherent_dma_mask	= DMA_BIT_MASK(32), | 
|  | 721 | .dma_mask		= &ep93xx_fb_device.dev.coherent_dma_mask, | 
|  | 722 | }, | 
|  | 723 | .num_resources		= ARRAY_SIZE(ep93xx_fb_resource), | 
|  | 724 | .resource		= ep93xx_fb_resource, | 
|  | 725 | }; | 
|  | 726 |  | 
|  | 727 | void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data) | 
|  | 728 | { | 
|  | 729 | ep93xxfb_data = *data; | 
|  | 730 | platform_device_register(&ep93xx_fb_device); | 
|  | 731 | } | 
|  | 732 |  | 
| Hartley Sweeten | 12f56c6 | 2009-10-28 21:04:46 +0100 | [diff] [blame] | 733 |  | 
|  | 734 | /************************************************************************* | 
|  | 735 | * EP93xx matrix keypad peripheral handling | 
|  | 736 | *************************************************************************/ | 
|  | 737 | static struct resource ep93xx_keypad_resource[] = { | 
|  | 738 | { | 
|  | 739 | .start	= EP93XX_KEY_MATRIX_PHYS_BASE, | 
|  | 740 | .end	= EP93XX_KEY_MATRIX_PHYS_BASE + 0x0c - 1, | 
|  | 741 | .flags	= IORESOURCE_MEM, | 
|  | 742 | }, { | 
|  | 743 | .start	= IRQ_EP93XX_KEY, | 
|  | 744 | .end	= IRQ_EP93XX_KEY, | 
|  | 745 | .flags	= IORESOURCE_IRQ, | 
|  | 746 | }, | 
|  | 747 | }; | 
|  | 748 |  | 
|  | 749 | static struct platform_device ep93xx_keypad_device = { | 
|  | 750 | .name			= "ep93xx-keypad", | 
|  | 751 | .id			= -1, | 
|  | 752 | .num_resources		= ARRAY_SIZE(ep93xx_keypad_resource), | 
|  | 753 | .resource		= ep93xx_keypad_resource, | 
|  | 754 | }; | 
|  | 755 |  | 
|  | 756 | void __init ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data) | 
|  | 757 | { | 
|  | 758 | ep93xx_keypad_device.dev.platform_data = data; | 
|  | 759 | platform_device_register(&ep93xx_keypad_device); | 
|  | 760 | } | 
|  | 761 |  | 
|  | 762 | int ep93xx_keypad_acquire_gpio(struct platform_device *pdev) | 
|  | 763 | { | 
|  | 764 | int err; | 
|  | 765 | int i; | 
|  | 766 |  | 
|  | 767 | for (i = 0; i < 8; i++) { | 
|  | 768 | err = gpio_request(EP93XX_GPIO_LINE_C(i), dev_name(&pdev->dev)); | 
|  | 769 | if (err) | 
|  | 770 | goto fail_gpio_c; | 
|  | 771 | err = gpio_request(EP93XX_GPIO_LINE_D(i), dev_name(&pdev->dev)); | 
|  | 772 | if (err) | 
|  | 773 | goto fail_gpio_d; | 
|  | 774 | } | 
|  | 775 |  | 
|  | 776 | /* Enable the keypad controller; GPIO ports C and D used for keypad */ | 
|  | 777 | ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_KEYS | | 
|  | 778 | EP93XX_SYSCON_DEVCFG_GONK); | 
|  | 779 |  | 
|  | 780 | return 0; | 
|  | 781 |  | 
|  | 782 | fail_gpio_d: | 
|  | 783 | gpio_free(EP93XX_GPIO_LINE_C(i)); | 
|  | 784 | fail_gpio_c: | 
|  | 785 | for ( ; i >= 0; --i) { | 
|  | 786 | gpio_free(EP93XX_GPIO_LINE_C(i)); | 
|  | 787 | gpio_free(EP93XX_GPIO_LINE_D(i)); | 
|  | 788 | } | 
|  | 789 | return err; | 
|  | 790 | } | 
|  | 791 | EXPORT_SYMBOL(ep93xx_keypad_acquire_gpio); | 
|  | 792 |  | 
|  | 793 | void ep93xx_keypad_release_gpio(struct platform_device *pdev) | 
|  | 794 | { | 
|  | 795 | int i; | 
|  | 796 |  | 
|  | 797 | for (i = 0; i < 8; i++) { | 
|  | 798 | gpio_free(EP93XX_GPIO_LINE_C(i)); | 
|  | 799 | gpio_free(EP93XX_GPIO_LINE_D(i)); | 
|  | 800 | } | 
|  | 801 |  | 
|  | 802 | /* Disable the keypad controller; GPIO ports C and D used for GPIO */ | 
|  | 803 | ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS | | 
|  | 804 | EP93XX_SYSCON_DEVCFG_GONK); | 
|  | 805 | } | 
|  | 806 | EXPORT_SYMBOL(ep93xx_keypad_release_gpio); | 
|  | 807 |  | 
|  | 808 |  | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 809 | extern void ep93xx_gpio_init(void); | 
| Lennert Buytenhek | 1f64eb3 | 2006-06-24 10:33:03 +0100 | [diff] [blame] | 810 |  | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 811 | void __init ep93xx_init_devices(void) | 
|  | 812 | { | 
| Hartley Sweeten | 02239f0 | 2009-07-08 02:00:49 +0100 | [diff] [blame] | 813 | /* Disallow access to MaverickCrunch initially */ | 
|  | 814 | ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_CPENA); | 
| Lennert Buytenhek | aee85fe | 2006-03-26 23:16:39 +0100 | [diff] [blame] | 815 |  | 
| Ryan Mallon | b685004 | 2008-04-16 02:56:35 +0100 | [diff] [blame] | 816 | ep93xx_gpio_init(); | 
|  | 817 |  | 
| Lennert Buytenhek | aee85fe | 2006-03-26 23:16:39 +0100 | [diff] [blame] | 818 | amba_device_register(&uart1_device, &iomem_resource); | 
|  | 819 | amba_device_register(&uart2_device, &iomem_resource); | 
|  | 820 | amba_device_register(&uart3_device, &iomem_resource); | 
| Lennert Buytenhek | 4165813 | 2006-04-02 16:17:34 +0100 | [diff] [blame] | 821 |  | 
|  | 822 | platform_device_register(&ep93xx_rtc_device); | 
| Lennert Buytenhek | 1f64eb3 | 2006-06-24 10:33:03 +0100 | [diff] [blame] | 823 | platform_device_register(&ep93xx_ohci_device); | 
| Hartley Sweeten | 3aa7a9a | 2009-07-20 18:22:36 +0100 | [diff] [blame] | 824 | platform_device_register(&ep93xx_leds); | 
| Lennert Buytenhek | e7736d4 | 2006-03-20 17:10:13 +0000 | [diff] [blame] | 825 | } |