Blame view
drivers/mfd/asic3.c
25.9 KB
fa9ff4b18 ASIC3 driver |
1 2 3 4 5 6 7 8 9 10 11 |
/* * driver/mfd/asic3.c * * Compaq ASIC3 support. * * 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. * * Copyright 2001 Compaq Computer Corporation. * Copyright 2004-2005 Phil Blundell |
6f2384c4b mfd: asic3 gpioli... |
12 |
* Copyright 2007-2008 OpenedHand Ltd. |
fa9ff4b18 ASIC3 driver |
13 14 15 16 17 |
* * Authors: Phil Blundell <pb@handhelds.org>, * Samuel Ortiz <sameo@openedhand.com> * */ |
fa9ff4b18 ASIC3 driver |
18 |
#include <linux/kernel.h> |
9461f65a8 mfd: asic3: enabl... |
19 |
#include <linux/delay.h> |
fa9ff4b18 ASIC3 driver |
20 |
#include <linux/irq.h> |
6f2384c4b mfd: asic3 gpioli... |
21 |
#include <linux/gpio.h> |
5d4a357d8 mfd: Add export.h... |
22 |
#include <linux/export.h> |
fa9ff4b18 ASIC3 driver |
23 |
#include <linux/io.h> |
5a0e3ad6a include cleanup: ... |
24 |
#include <linux/slab.h> |
fa9ff4b18 ASIC3 driver |
25 26 27 28 |
#include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/mfd/asic3.h> |
9461f65a8 mfd: asic3: enabl... |
29 30 |
#include <linux/mfd/core.h> #include <linux/mfd/ds1wm.h> |
09f05ce85 mfd: asic3: enabl... |
31 |
#include <linux/mfd/tmio.h> |
fa9ff4b18 ASIC3 driver |
32 |
|
e956a2a87 mfd: asic3: add c... |
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
enum { ASIC3_CLOCK_SPI, ASIC3_CLOCK_OWM, ASIC3_CLOCK_PWM0, ASIC3_CLOCK_PWM1, ASIC3_CLOCK_LED0, ASIC3_CLOCK_LED1, ASIC3_CLOCK_LED2, ASIC3_CLOCK_SD_HOST, ASIC3_CLOCK_SD_BUS, ASIC3_CLOCK_SMBUS, ASIC3_CLOCK_EX0, ASIC3_CLOCK_EX1, }; struct asic3_clk { int enabled; unsigned int cdex; unsigned long rate; }; #define INIT_CDEX(_name, _rate) \ [ASIC3_CLOCK_##_name] = { \ .cdex = CLOCK_CDEX_##_name, \ .rate = _rate, \ } |
59f2ad2e0 mfd: Staticise un... |
59 |
static struct asic3_clk asic3_clk_init[] __initdata = { |
e956a2a87 mfd: asic3: add c... |
60 61 62 63 64 65 66 67 68 69 70 71 72 |
INIT_CDEX(SPI, 0), INIT_CDEX(OWM, 5000000), INIT_CDEX(PWM0, 0), INIT_CDEX(PWM1, 0), INIT_CDEX(LED0, 0), INIT_CDEX(LED1, 0), INIT_CDEX(LED2, 0), INIT_CDEX(SD_HOST, 24576000), INIT_CDEX(SD_BUS, 12288000), INIT_CDEX(SMBUS, 0), INIT_CDEX(EX0, 32768), INIT_CDEX(EX1, 24576000), }; |
6f2384c4b mfd: asic3 gpioli... |
73 74 75 76 77 78 79 80 81 |
struct asic3 { void __iomem *mapping; unsigned int bus_shift; unsigned int irq_nr; unsigned int irq_base; spinlock_t lock; u16 irq_bothedge[4]; struct gpio_chip gpio; struct device *dev; |
64e8867ba mfd: tmio_mmc har... |
82 |
void __iomem *tmio_cnf; |
e956a2a87 mfd: asic3: add c... |
83 84 |
struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)]; |
6f2384c4b mfd: asic3 gpioli... |
85 86 87 |
}; static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); |
13ca4f661 mfd: Add ASIC3 LE... |
88 |
void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value) |
fa9ff4b18 ASIC3 driver |
89 |
{ |
b32661e06 mfd/asic3: ioread... |
90 |
iowrite16(value, asic->mapping + |
fa9ff4b18 ASIC3 driver |
91 92 |
(reg >> asic->bus_shift)); } |
13ca4f661 mfd: Add ASIC3 LE... |
93 |
EXPORT_SYMBOL_GPL(asic3_write_register); |
fa9ff4b18 ASIC3 driver |
94 |
|
13ca4f661 mfd: Add ASIC3 LE... |
95 |
u32 asic3_read_register(struct asic3 *asic, unsigned int reg) |
fa9ff4b18 ASIC3 driver |
96 |
{ |
b32661e06 mfd/asic3: ioread... |
97 |
return ioread16(asic->mapping + |
fa9ff4b18 ASIC3 driver |
98 99 |
(reg >> asic->bus_shift)); } |
13ca4f661 mfd: Add ASIC3 LE... |
100 |
EXPORT_SYMBOL_GPL(asic3_read_register); |
fa9ff4b18 ASIC3 driver |
101 |
|
59f2ad2e0 mfd: Staticise un... |
102 |
static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) |
6483c1b5e mfd: asic3: add a... |
103 104 105 106 107 108 109 110 111 112 113 114 115 |
{ unsigned long flags; u32 val; spin_lock_irqsave(&asic->lock, flags); val = asic3_read_register(asic, reg); if (set) val |= bits; else val &= ~bits; asic3_write_register(asic, reg, val); spin_unlock_irqrestore(&asic->lock, flags); } |
fa9ff4b18 ASIC3 driver |
116 117 |
/* IRQs */ #define MAX_ASIC_ISR_LOOPS 20 |
3b8139f8b mfd: Use uppercas... |
118 119 |
#define ASIC3_GPIO_BASE_INCR \ (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE) |
fa9ff4b18 ASIC3 driver |
120 121 122 123 124 125 126 127 128 |
static void asic3_irq_flip_edge(struct asic3 *asic, u32 base, int bit) { u16 edge; unsigned long flags; spin_lock_irqsave(&asic->lock, flags); edge = asic3_read_register(asic, |
3b8139f8b mfd: Use uppercas... |
129 |
base + ASIC3_GPIO_EDGE_TRIGGER); |
fa9ff4b18 ASIC3 driver |
130 131 |
edge ^= bit; asic3_write_register(asic, |
3b8139f8b mfd: Use uppercas... |
132 |
base + ASIC3_GPIO_EDGE_TRIGGER, edge); |
fa9ff4b18 ASIC3 driver |
133 134 135 136 137 |
spin_unlock_irqrestore(&asic->lock, flags); } static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) { |
52a7d6077 mfd: asic3: Clean... |
138 139 |
struct asic3 *asic = irq_desc_get_handler_data(desc); struct irq_data *data = irq_desc_get_irq_data(desc); |
fa9ff4b18 ASIC3 driver |
140 141 |
int iter, i; unsigned long flags; |
fa9ff4b18 ASIC3 driver |
142 |
|
a09aee8b6 mfd: Fix asic3 bu... |
143 |
data->chip->irq_ack(data); |
fa9ff4b18 ASIC3 driver |
144 145 146 147 148 149 150 |
for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { u32 status; int bank; spin_lock_irqsave(&asic->lock, flags); status = asic3_read_register(asic, |
3b8139f8b mfd: Use uppercas... |
151 |
ASIC3_OFFSET(INTR, P_INT_STAT)); |
fa9ff4b18 ASIC3 driver |
152 153 154 155 156 157 158 159 160 161 |
spin_unlock_irqrestore(&asic->lock, flags); /* Check all ten register bits */ if ((status & 0x3ff) == 0) break; /* Handle GPIO IRQs */ for (bank = 0; bank < ASIC3_NUM_GPIO_BANKS; bank++) { if (status & (1 << bank)) { unsigned long base, istat; |
3b8139f8b mfd: Use uppercas... |
162 163 |
base = ASIC3_GPIO_A_BASE + bank * ASIC3_GPIO_BASE_INCR; |
fa9ff4b18 ASIC3 driver |
164 165 166 167 |
spin_lock_irqsave(&asic->lock, flags); istat = asic3_read_register(asic, base + |
3b8139f8b mfd: Use uppercas... |
168 |
ASIC3_GPIO_INT_STATUS); |
fa9ff4b18 ASIC3 driver |
169 170 171 |
/* Clearing IntStatus */ asic3_write_register(asic, base + |
3b8139f8b mfd: Use uppercas... |
172 |
ASIC3_GPIO_INT_STATUS, 0); |
fa9ff4b18 ASIC3 driver |
173 174 175 176 177 178 179 180 181 182 183 184 |
spin_unlock_irqrestore(&asic->lock, flags); for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) { int bit = (1 << i); unsigned int irqnr; if (!(istat & bit)) continue; irqnr = asic->irq_base + (ASIC3_GPIOS_PER_BANK * bank) + i; |
52a7d6077 mfd: asic3: Clean... |
185 |
generic_handle_irq(irqnr); |
fa9ff4b18 ASIC3 driver |
186 187 188 189 190 191 192 193 194 195 |
if (asic->irq_bothedge[bank] & bit) asic3_irq_flip_edge(asic, base, bit); } } } /* Handle remaining IRQs in the status register */ for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { /* They start at bit 4 and go up */ |
52a7d6077 mfd: asic3: Clean... |
196 197 |
if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) generic_handle_irq(asic->irq_base + i); |
fa9ff4b18 ASIC3 driver |
198 199 200 201 |
} } if (iter >= MAX_ASIC_ISR_LOOPS) |
24f4f2eef mfd: use dev_* ma... |
202 203 |
dev_err(asic->dev, "interrupt processing overrun "); |
fa9ff4b18 ASIC3 driver |
204 205 206 207 208 209 210 |
} static inline int asic3_irq_to_bank(struct asic3 *asic, int irq) { int n; n = (irq - asic->irq_base) >> 4; |
3b8139f8b mfd: Use uppercas... |
211 |
return (n * (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE)); |
fa9ff4b18 ASIC3 driver |
212 213 214 215 216 217 |
} static inline int asic3_irq_to_index(struct asic3 *asic, int irq) { return (irq - asic->irq_base) & 0xf; } |
0f76aaebe mfd: Convert ASIC... |
218 |
static void asic3_mask_gpio_irq(struct irq_data *data) |
fa9ff4b18 ASIC3 driver |
219 |
{ |
0f76aaebe mfd: Convert ASIC... |
220 |
struct asic3 *asic = irq_data_get_irq_chip_data(data); |
fa9ff4b18 ASIC3 driver |
221 222 |
u32 val, bank, index; unsigned long flags; |
0f76aaebe mfd: Convert ASIC... |
223 224 |
bank = asic3_irq_to_bank(asic, data->irq); index = asic3_irq_to_index(asic, data->irq); |
fa9ff4b18 ASIC3 driver |
225 226 |
spin_lock_irqsave(&asic->lock, flags); |
3b8139f8b mfd: Use uppercas... |
227 |
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); |
fa9ff4b18 ASIC3 driver |
228 |
val |= 1 << index; |
3b8139f8b mfd: Use uppercas... |
229 |
asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); |
fa9ff4b18 ASIC3 driver |
230 231 |
spin_unlock_irqrestore(&asic->lock, flags); } |
0f76aaebe mfd: Convert ASIC... |
232 |
static void asic3_mask_irq(struct irq_data *data) |
fa9ff4b18 ASIC3 driver |
233 |
{ |
0f76aaebe mfd: Convert ASIC... |
234 |
struct asic3 *asic = irq_data_get_irq_chip_data(data); |
fa9ff4b18 ASIC3 driver |
235 236 237 238 239 |
int regval; unsigned long flags; spin_lock_irqsave(&asic->lock, flags); regval = asic3_read_register(asic, |
3b8139f8b mfd: Use uppercas... |
240 241 |
ASIC3_INTR_BASE + ASIC3_INTR_INT_MASK); |
fa9ff4b18 ASIC3 driver |
242 243 |
regval &= ~(ASIC3_INTMASK_MASK0 << |
0f76aaebe mfd: Convert ASIC... |
244 |
(data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); |
fa9ff4b18 ASIC3 driver |
245 246 |
asic3_write_register(asic, |
3b8139f8b mfd: Use uppercas... |
247 248 |
ASIC3_INTR_BASE + ASIC3_INTR_INT_MASK, |
fa9ff4b18 ASIC3 driver |
249 250 251 |
regval); spin_unlock_irqrestore(&asic->lock, flags); } |
0f76aaebe mfd: Convert ASIC... |
252 |
static void asic3_unmask_gpio_irq(struct irq_data *data) |
fa9ff4b18 ASIC3 driver |
253 |
{ |
0f76aaebe mfd: Convert ASIC... |
254 |
struct asic3 *asic = irq_data_get_irq_chip_data(data); |
fa9ff4b18 ASIC3 driver |
255 256 |
u32 val, bank, index; unsigned long flags; |
0f76aaebe mfd: Convert ASIC... |
257 258 |
bank = asic3_irq_to_bank(asic, data->irq); index = asic3_irq_to_index(asic, data->irq); |
fa9ff4b18 ASIC3 driver |
259 260 |
spin_lock_irqsave(&asic->lock, flags); |
3b8139f8b mfd: Use uppercas... |
261 |
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); |
fa9ff4b18 ASIC3 driver |
262 |
val &= ~(1 << index); |
3b8139f8b mfd: Use uppercas... |
263 |
asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); |
fa9ff4b18 ASIC3 driver |
264 265 |
spin_unlock_irqrestore(&asic->lock, flags); } |
0f76aaebe mfd: Convert ASIC... |
266 |
static void asic3_unmask_irq(struct irq_data *data) |
fa9ff4b18 ASIC3 driver |
267 |
{ |
0f76aaebe mfd: Convert ASIC... |
268 |
struct asic3 *asic = irq_data_get_irq_chip_data(data); |
fa9ff4b18 ASIC3 driver |
269 270 271 272 273 |
int regval; unsigned long flags; spin_lock_irqsave(&asic->lock, flags); regval = asic3_read_register(asic, |
3b8139f8b mfd: Use uppercas... |
274 275 |
ASIC3_INTR_BASE + ASIC3_INTR_INT_MASK); |
fa9ff4b18 ASIC3 driver |
276 277 |
regval |= (ASIC3_INTMASK_MASK0 << |
0f76aaebe mfd: Convert ASIC... |
278 |
(data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); |
fa9ff4b18 ASIC3 driver |
279 280 |
asic3_write_register(asic, |
3b8139f8b mfd: Use uppercas... |
281 282 |
ASIC3_INTR_BASE + ASIC3_INTR_INT_MASK, |
fa9ff4b18 ASIC3 driver |
283 284 285 |
regval); spin_unlock_irqrestore(&asic->lock, flags); } |
0f76aaebe mfd: Convert ASIC... |
286 |
static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type) |
fa9ff4b18 ASIC3 driver |
287 |
{ |
0f76aaebe mfd: Convert ASIC... |
288 |
struct asic3 *asic = irq_data_get_irq_chip_data(data); |
fa9ff4b18 ASIC3 driver |
289 290 291 |
u32 bank, index; u16 trigger, level, edge, bit; unsigned long flags; |
0f76aaebe mfd: Convert ASIC... |
292 293 |
bank = asic3_irq_to_bank(asic, data->irq); index = asic3_irq_to_index(asic, data->irq); |
fa9ff4b18 ASIC3 driver |
294 295 296 297 |
bit = 1<<index; spin_lock_irqsave(&asic->lock, flags); level = asic3_read_register(asic, |
3b8139f8b mfd: Use uppercas... |
298 |
bank + ASIC3_GPIO_LEVEL_TRIGGER); |
fa9ff4b18 ASIC3 driver |
299 |
edge = asic3_read_register(asic, |
3b8139f8b mfd: Use uppercas... |
300 |
bank + ASIC3_GPIO_EDGE_TRIGGER); |
fa9ff4b18 ASIC3 driver |
301 |
trigger = asic3_read_register(asic, |
3b8139f8b mfd: Use uppercas... |
302 |
bank + ASIC3_GPIO_TRIGGER_TYPE); |
0f76aaebe mfd: Convert ASIC... |
303 |
asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit; |
fa9ff4b18 ASIC3 driver |
304 |
|
6cab48602 [ARM] 5179/1: Rep... |
305 |
if (type == IRQ_TYPE_EDGE_RISING) { |
fa9ff4b18 ASIC3 driver |
306 307 |
trigger |= bit; edge |= bit; |
6cab48602 [ARM] 5179/1: Rep... |
308 |
} else if (type == IRQ_TYPE_EDGE_FALLING) { |
fa9ff4b18 ASIC3 driver |
309 310 |
trigger |= bit; edge &= ~bit; |
6cab48602 [ARM] 5179/1: Rep... |
311 |
} else if (type == IRQ_TYPE_EDGE_BOTH) { |
fa9ff4b18 ASIC3 driver |
312 |
trigger |= bit; |
0f76aaebe mfd: Convert ASIC... |
313 |
if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base)) |
fa9ff4b18 ASIC3 driver |
314 315 316 |
edge &= ~bit; else edge |= bit; |
0f76aaebe mfd: Convert ASIC... |
317 |
asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit; |
6cab48602 [ARM] 5179/1: Rep... |
318 |
} else if (type == IRQ_TYPE_LEVEL_LOW) { |
fa9ff4b18 ASIC3 driver |
319 320 |
trigger &= ~bit; level &= ~bit; |
6cab48602 [ARM] 5179/1: Rep... |
321 |
} else if (type == IRQ_TYPE_LEVEL_HIGH) { |
fa9ff4b18 ASIC3 driver |
322 323 324 325 |
trigger &= ~bit; level |= bit; } else { /* |
6cab48602 [ARM] 5179/1: Rep... |
326 |
* if type == IRQ_TYPE_NONE, we should mask interrupts, but |
fa9ff4b18 ASIC3 driver |
327 328 329 |
* be careful to not unmask them if mask was also called. * Probably need internal state for mask. */ |
24f4f2eef mfd: use dev_* ma... |
330 331 |
dev_notice(asic->dev, "irq type not changed "); |
fa9ff4b18 ASIC3 driver |
332 |
} |
3b8139f8b mfd: Use uppercas... |
333 |
asic3_write_register(asic, bank + ASIC3_GPIO_LEVEL_TRIGGER, |
fa9ff4b18 ASIC3 driver |
334 |
level); |
3b8139f8b mfd: Use uppercas... |
335 |
asic3_write_register(asic, bank + ASIC3_GPIO_EDGE_TRIGGER, |
fa9ff4b18 ASIC3 driver |
336 |
edge); |
3b8139f8b mfd: Use uppercas... |
337 |
asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE, |
fa9ff4b18 ASIC3 driver |
338 339 340 341 342 343 344 |
trigger); spin_unlock_irqrestore(&asic->lock, flags); return 0; } static struct irq_chip asic3_gpio_irq_chip = { .name = "ASIC3-GPIO", |
0f76aaebe mfd: Convert ASIC... |
345 346 347 348 |
.irq_ack = asic3_mask_gpio_irq, .irq_mask = asic3_mask_gpio_irq, .irq_unmask = asic3_unmask_gpio_irq, .irq_set_type = asic3_gpio_irq_type, |
fa9ff4b18 ASIC3 driver |
349 350 351 352 |
}; static struct irq_chip asic3_irq_chip = { .name = "ASIC3", |
0f76aaebe mfd: Convert ASIC... |
353 354 355 |
.irq_ack = asic3_mask_irq, .irq_mask = asic3_mask_irq, .irq_unmask = asic3_unmask_irq, |
fa9ff4b18 ASIC3 driver |
356 |
}; |
065032f61 mfd: move asic3 p... |
357 |
static int __init asic3_irq_probe(struct platform_device *pdev) |
fa9ff4b18 ASIC3 driver |
358 359 360 361 |
{ struct asic3 *asic = platform_get_drvdata(pdev); unsigned long clksel = 0; unsigned int irq, irq_base; |
c491b2ffa asic3: platform_g... |
362 |
int ret; |
fa9ff4b18 ASIC3 driver |
363 |
|
c491b2ffa asic3: platform_g... |
364 365 366 367 |
ret = platform_get_irq(pdev, 0); if (ret < 0) return ret; asic->irq_nr = ret; |
fa9ff4b18 ASIC3 driver |
368 369 370 371 372 373 374 375 376 377 |
/* turn on clock to IRQ controller */ clksel |= CLOCK_SEL_CX; asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel); irq_base = asic->irq_base; for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { if (irq < asic->irq_base + ASIC3_NUM_GPIOS) |
d5bb12216 mfd: Cleanup irq ... |
378 |
irq_set_chip(irq, &asic3_gpio_irq_chip); |
fa9ff4b18 ASIC3 driver |
379 |
else |
d5bb12216 mfd: Cleanup irq ... |
380 |
irq_set_chip(irq, &asic3_irq_chip); |
fa9ff4b18 ASIC3 driver |
381 |
|
d5bb12216 mfd: Cleanup irq ... |
382 383 |
irq_set_chip_data(irq, asic); irq_set_handler(irq, handle_level_irq); |
fa9ff4b18 ASIC3 driver |
384 385 |
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } |
3b8139f8b mfd: Use uppercas... |
386 |
asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), |
fa9ff4b18 ASIC3 driver |
387 |
ASIC3_INTMASK_GINTMASK); |
d5bb12216 mfd: Cleanup irq ... |
388 389 390 |
irq_set_chained_handler(asic->irq_nr, asic3_irq_demux); irq_set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); irq_set_handler_data(asic->irq_nr, asic); |
fa9ff4b18 ASIC3 driver |
391 392 393 394 395 396 397 398 399 400 401 402 403 |
return 0; } static void asic3_irq_remove(struct platform_device *pdev) { struct asic3 *asic = platform_get_drvdata(pdev); unsigned int irq, irq_base; irq_base = asic->irq_base; for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { set_irq_flags(irq, 0); |
d6f7ce9f7 mfd: Fold irq_set... |
404 |
irq_set_chip_and_handler(irq, NULL, NULL); |
d5bb12216 mfd: Cleanup irq ... |
405 |
irq_set_chip_data(irq, NULL); |
fa9ff4b18 ASIC3 driver |
406 |
} |
d5bb12216 mfd: Cleanup irq ... |
407 |
irq_set_chained_handler(asic->irq_nr, NULL); |
fa9ff4b18 ASIC3 driver |
408 409 410 |
} /* GPIOs */ |
6f2384c4b mfd: asic3 gpioli... |
411 412 413 414 415 416 417 418 419 420 |
static int asic3_gpio_direction(struct gpio_chip *chip, unsigned offset, int out) { u32 mask = ASIC3_GPIO_TO_MASK(offset), out_reg; unsigned int gpio_base; unsigned long flags; struct asic3 *asic; asic = container_of(chip, struct asic3, gpio); gpio_base = ASIC3_GPIO_TO_BASE(offset); |
3b8139f8b mfd: Use uppercas... |
421 |
if (gpio_base > ASIC3_GPIO_D_BASE) { |
24f4f2eef mfd: use dev_* ma... |
422 423 424 |
dev_err(asic->dev, "Invalid base (0x%x) for gpio %d ", gpio_base, offset); |
6f2384c4b mfd: asic3 gpioli... |
425 426 427 428 |
return -EINVAL; } spin_lock_irqsave(&asic->lock, flags); |
3b8139f8b mfd: Use uppercas... |
429 |
out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION); |
6f2384c4b mfd: asic3 gpioli... |
430 431 432 433 434 435 |
/* Input is 0, Output is 1 */ if (out) out_reg |= mask; else out_reg &= ~mask; |
3b8139f8b mfd: Use uppercas... |
436 |
asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg); |
6f2384c4b mfd: asic3 gpioli... |
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 |
spin_unlock_irqrestore(&asic->lock, flags); return 0; } static int asic3_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { return asic3_gpio_direction(chip, offset, 0); } static int asic3_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { return asic3_gpio_direction(chip, offset, 1); } static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset) { unsigned int gpio_base; u32 mask = ASIC3_GPIO_TO_MASK(offset); struct asic3 *asic; asic = container_of(chip, struct asic3, gpio); gpio_base = ASIC3_GPIO_TO_BASE(offset); |
3b8139f8b mfd: Use uppercas... |
465 |
if (gpio_base > ASIC3_GPIO_D_BASE) { |
24f4f2eef mfd: use dev_* ma... |
466 467 468 |
dev_err(asic->dev, "Invalid base (0x%x) for gpio %d ", gpio_base, offset); |
6f2384c4b mfd: asic3 gpioli... |
469 470 |
return -EINVAL; } |
3b8139f8b mfd: Use uppercas... |
471 |
return asic3_read_register(asic, gpio_base + ASIC3_GPIO_STATUS) & mask; |
6f2384c4b mfd: asic3 gpioli... |
472 473 474 475 476 477 478 479 480 481 482 483 |
} static void asic3_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { u32 mask, out_reg; unsigned int gpio_base; unsigned long flags; struct asic3 *asic; asic = container_of(chip, struct asic3, gpio); gpio_base = ASIC3_GPIO_TO_BASE(offset); |
3b8139f8b mfd: Use uppercas... |
484 |
if (gpio_base > ASIC3_GPIO_D_BASE) { |
24f4f2eef mfd: use dev_* ma... |
485 486 487 |
dev_err(asic->dev, "Invalid base (0x%x) for gpio %d ", gpio_base, offset); |
6f2384c4b mfd: asic3 gpioli... |
488 489 490 491 492 493 |
return; } mask = ASIC3_GPIO_TO_MASK(offset); spin_lock_irqsave(&asic->lock, flags); |
3b8139f8b mfd: Use uppercas... |
494 |
out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT); |
6f2384c4b mfd: asic3 gpioli... |
495 496 497 498 499 |
if (value) out_reg |= mask; else out_reg &= ~mask; |
3b8139f8b mfd: Use uppercas... |
500 |
asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg); |
6f2384c4b mfd: asic3 gpioli... |
501 502 503 504 505 |
spin_unlock_irqrestore(&asic->lock, flags); return; } |
065032f61 mfd: move asic3 p... |
506 507 |
static __init int asic3_gpio_probe(struct platform_device *pdev, u16 *gpio_config, int num) |
fa9ff4b18 ASIC3 driver |
508 |
{ |
fa9ff4b18 ASIC3 driver |
509 |
struct asic3 *asic = platform_get_drvdata(pdev); |
3b26bf172 mfd: New asic3 gp... |
510 511 512 513 |
u16 alt_reg[ASIC3_NUM_GPIO_BANKS]; u16 out_reg[ASIC3_NUM_GPIO_BANKS]; u16 dir_reg[ASIC3_NUM_GPIO_BANKS]; int i; |
fa9ff4b18 ASIC3 driver |
514 |
|
59f0cb0fd [ARM] remove memz... |
515 516 517 |
memset(alt_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); memset(out_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); memset(dir_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); |
3b26bf172 mfd: New asic3 gp... |
518 519 |
/* Enable all GPIOs */ |
3b8139f8b mfd: Use uppercas... |
520 521 522 523 |
asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, MASK), 0xffff); asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, MASK), 0xffff); asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, MASK), 0xffff); asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, MASK), 0xffff); |
fa9ff4b18 ASIC3 driver |
524 |
|
3b26bf172 mfd: New asic3 gp... |
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
for (i = 0; i < num; i++) { u8 alt, pin, dir, init, bank_num, bit_num; u16 config = gpio_config[i]; pin = ASIC3_CONFIG_GPIO_PIN(config); alt = ASIC3_CONFIG_GPIO_ALT(config); dir = ASIC3_CONFIG_GPIO_DIR(config); init = ASIC3_CONFIG_GPIO_INIT(config); bank_num = ASIC3_GPIO_TO_BANK(pin); bit_num = ASIC3_GPIO_TO_BIT(pin); alt_reg[bank_num] |= (alt << bit_num); out_reg[bank_num] |= (init << bit_num); dir_reg[bank_num] |= (dir << bit_num); } for (i = 0; i < ASIC3_NUM_GPIO_BANKS; i++) { asic3_write_register(asic, ASIC3_BANK_TO_BASE(i) + |
3b8139f8b mfd: Use uppercas... |
545 |
ASIC3_GPIO_DIRECTION, |
3b26bf172 mfd: New asic3 gp... |
546 547 |
dir_reg[i]); asic3_write_register(asic, |
3b8139f8b mfd: Use uppercas... |
548 |
ASIC3_BANK_TO_BASE(i) + ASIC3_GPIO_OUT, |
3b26bf172 mfd: New asic3 gp... |
549 550 551 |
out_reg[i]); asic3_write_register(asic, ASIC3_BANK_TO_BASE(i) + |
3b8139f8b mfd: Use uppercas... |
552 |
ASIC3_GPIO_ALT_FUNCTION, |
3b26bf172 mfd: New asic3 gp... |
553 |
alt_reg[i]); |
fa9ff4b18 ASIC3 driver |
554 |
} |
6f2384c4b mfd: asic3 gpioli... |
555 |
return gpiochip_add(&asic->gpio); |
fa9ff4b18 ASIC3 driver |
556 |
} |
6f2384c4b mfd: asic3 gpioli... |
557 |
static int asic3_gpio_remove(struct platform_device *pdev) |
fa9ff4b18 ASIC3 driver |
558 |
{ |
6f2384c4b mfd: asic3 gpioli... |
559 560 561 |
struct asic3 *asic = platform_get_drvdata(pdev); return gpiochip_remove(&asic->gpio); |
fa9ff4b18 ASIC3 driver |
562 |
} |
c29a81270 mfd: Make asic3_c... |
563 |
static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk) |
e956a2a87 mfd: asic3: add c... |
564 565 566 567 568 569 570 571 572 573 574 |
{ unsigned long flags; u32 cdex; spin_lock_irqsave(&asic->lock, flags); if (clk->enabled++ == 0) { cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); cdex |= clk->cdex; asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); } spin_unlock_irqrestore(&asic->lock, flags); |
e956a2a87 mfd: asic3: add c... |
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
} static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk) { unsigned long flags; u32 cdex; WARN_ON(clk->enabled == 0); spin_lock_irqsave(&asic->lock, flags); if (--clk->enabled == 0) { cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); cdex &= ~clk->cdex; asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); } spin_unlock_irqrestore(&asic->lock, flags); } |
fa9ff4b18 ASIC3 driver |
592 |
|
9461f65a8 mfd: asic3: enabl... |
593 594 595 |
/* MFD cells (SPI, PWM, LED, DS1WM, MMC) */ static struct ds1wm_driver_data ds1wm_pdata = { .active_high = 1, |
f607e7fc5 w1: ds1wm: add a ... |
596 |
.reset_recover_delay = 1, |
9461f65a8 mfd: asic3: enabl... |
597 598 599 600 601 602 603 604 605 606 |
}; static struct resource ds1wm_resources[] = { { .start = ASIC3_OWM_BASE, .end = ASIC3_OWM_BASE + 0x13, .flags = IORESOURCE_MEM, }, { .start = ASIC3_IRQ_OWM, |
fe421425d mfd: Correct ASIC... |
607 |
.end = ASIC3_IRQ_OWM, |
9461f65a8 mfd: asic3: enabl... |
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 |
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, }, }; static int ds1wm_enable(struct platform_device *pdev) { struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); /* Turn on external clocks and the OWM clock */ asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_OWM]); msleep(1); /* Reset and enable DS1WM */ asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET), ASIC3_EXTCF_OWM_RESET, 1); msleep(1); asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET), ASIC3_EXTCF_OWM_RESET, 0); msleep(1); asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), ASIC3_EXTCF_OWM_EN, 1); msleep(1); return 0; } static int ds1wm_disable(struct platform_device *pdev) { struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), ASIC3_EXTCF_OWM_EN, 0); asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_OWM]); asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); return 0; } static struct mfd_cell asic3_cell_ds1wm = { .name = "ds1wm", .enable = ds1wm_enable, .disable = ds1wm_disable, |
121ea573a w1: Use device pl... |
654 655 |
.platform_data = &ds1wm_pdata, .pdata_size = sizeof(ds1wm_pdata), |
9461f65a8 mfd: asic3: enabl... |
656 657 658 |
.num_resources = ARRAY_SIZE(ds1wm_resources), .resources = ds1wm_resources, }; |
64e8867ba mfd: tmio_mmc har... |
659 660 661 662 663 664 665 666 667 668 669 670 671 |
static void asic3_mmc_pwr(struct platform_device *pdev, int state) { struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); tmio_core_mmc_pwr(asic->tmio_cnf, 1 - asic->bus_shift, state); } static void asic3_mmc_clk_div(struct platform_device *pdev, int state) { struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); tmio_core_mmc_clk_div(asic->tmio_cnf, 1 - asic->bus_shift, state); } |
09f05ce85 mfd: asic3: enabl... |
672 |
static struct tmio_mmc_data asic3_mmc_data = { |
64e8867ba mfd: tmio_mmc har... |
673 674 675 |
.hclk = 24576000, .set_pwr = asic3_mmc_pwr, .set_clk_div = asic3_mmc_clk_div, |
09f05ce85 mfd: asic3: enabl... |
676 677 678 679 680 681 682 683 684 |
}; static struct resource asic3_mmc_resources[] = { { .start = ASIC3_SD_CTRL_BASE, .end = ASIC3_SD_CTRL_BASE + 0x3ff, .flags = IORESOURCE_MEM, }, { |
09f05ce85 mfd: asic3: enabl... |
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 |
.start = 0, .end = 0, .flags = IORESOURCE_IRQ, }, }; static int asic3_mmc_enable(struct platform_device *pdev) { struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); /* Not sure if it must be done bit by bit, but leaving as-is */ asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), ASIC3_SDHWCTRL_LEVCD, 1); asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), ASIC3_SDHWCTRL_LEVWP, 1); asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), ASIC3_SDHWCTRL_SUSPEND, 0); asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), ASIC3_SDHWCTRL_PCLR, 0); asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); /* CLK32 used for card detection and for interruption detection * when HCLK is stopped. */ asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); msleep(1); /* HCLK 24.576 MHz, BCLK 12.288 MHz: */ asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), CLOCK_SEL_CX | CLOCK_SEL_SD_HCLK_SEL); asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); msleep(1); asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), ASIC3_EXTCF_SD_MEM_ENABLE, 1); /* Enable SD card slot 3.3V power supply */ asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), ASIC3_SDHWCTRL_SDPWR, 1); |
64e8867ba mfd: tmio_mmc har... |
726 727 728 |
/* ASIC3_SD_CTRL_BASE assumes 32-bit addressing, TMIO is 16-bit */ tmio_core_mmc_enable(asic->tmio_cnf, 1 - asic->bus_shift, ASIC3_SD_CTRL_BASE >> 1); |
09f05ce85 mfd: asic3: enabl... |
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 |
return 0; } static int asic3_mmc_disable(struct platform_device *pdev) { struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); /* Put in suspend mode */ asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), ASIC3_SDHWCTRL_SUSPEND, 1); /* Disable clocks */ asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); return 0; } static struct mfd_cell asic3_cell_mmc = { .name = "tmio-mmc", .enable = asic3_mmc_enable, .disable = asic3_mmc_disable, |
3c6e36537 mfd: Fix asic3 ba... |
752 753 |
.suspend = asic3_mmc_disable, .resume = asic3_mmc_enable, |
ec71974f2 mmc: Use device p... |
754 755 |
.platform_data = &asic3_mmc_data, .pdata_size = sizeof(asic3_mmc_data), |
09f05ce85 mfd: asic3: enabl... |
756 757 758 |
.num_resources = ARRAY_SIZE(asic3_mmc_resources), .resources = asic3_mmc_resources, }; |
13ca4f661 mfd: Add ASIC3 LE... |
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 |
static const int clock_ledn[ASIC3_NUM_LEDS] = { [0] = ASIC3_CLOCK_LED0, [1] = ASIC3_CLOCK_LED1, [2] = ASIC3_CLOCK_LED2, }; static int asic3_leds_enable(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); asic3_clk_enable(asic, &asic->clocks[clock_ledn[cell->id]]); return 0; } static int asic3_leds_disable(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]); return 0; } |
e0b13b5b6 mfd: Add asic3 ba... |
784 785 786 787 788 789 790 791 792 793 794 795 |
static int asic3_leds_suspend(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); while (asic3_gpio_get(&asic->gpio, ASIC3_GPIO(C, cell->id)) != 0) msleep(1); asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]); return 0; } |
13ca4f661 mfd: Add ASIC3 LE... |
796 797 798 799 800 801 |
static struct mfd_cell asic3_cell_leds[ASIC3_NUM_LEDS] = { [0] = { .name = "leds-asic3", .id = 0, .enable = asic3_leds_enable, .disable = asic3_leds_disable, |
e0b13b5b6 mfd: Add asic3 ba... |
802 803 |
.suspend = asic3_leds_suspend, .resume = asic3_leds_enable, |
13ca4f661 mfd: Add ASIC3 LE... |
804 805 806 807 808 809 |
}, [1] = { .name = "leds-asic3", .id = 1, .enable = asic3_leds_enable, .disable = asic3_leds_disable, |
e0b13b5b6 mfd: Add asic3 ba... |
810 811 |
.suspend = asic3_leds_suspend, .resume = asic3_leds_enable, |
13ca4f661 mfd: Add ASIC3 LE... |
812 813 814 815 816 817 |
}, [2] = { .name = "leds-asic3", .id = 2, .enable = asic3_leds_enable, .disable = asic3_leds_disable, |
e0b13b5b6 mfd: Add asic3 ba... |
818 819 |
.suspend = asic3_leds_suspend, .resume = asic3_leds_enable, |
13ca4f661 mfd: Add ASIC3 LE... |
820 821 |
}, }; |
9461f65a8 mfd: asic3: enabl... |
822 |
static int __init asic3_mfd_probe(struct platform_device *pdev, |
13ca4f661 mfd: Add ASIC3 LE... |
823 |
struct asic3_platform_data *pdata, |
9461f65a8 mfd: asic3: enabl... |
824 825 826 |
struct resource *mem) { struct asic3 *asic = platform_get_drvdata(pdev); |
09f05ce85 mfd: asic3: enabl... |
827 828 829 830 831 832 833 834 835 836 837 838 |
struct resource *mem_sdio; int irq, ret; mem_sdio = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!mem_sdio) dev_dbg(asic->dev, "no SDIO MEM resource "); irq = platform_get_irq(pdev, 1); if (irq < 0) dev_dbg(asic->dev, "no SDIO IRQ resource "); |
9461f65a8 mfd: asic3: enabl... |
839 840 841 842 843 844 845 |
/* DS1WM */ asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), ASIC3_EXTCF_OWM_SMB, 0); ds1wm_resources[0].start >>= asic->bus_shift; ds1wm_resources[0].end >>= asic->bus_shift; |
09f05ce85 mfd: asic3: enabl... |
846 |
/* MMC */ |
64e8867ba mfd: tmio_mmc har... |
847 |
asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) + |
74e32d1b6 mfd: Fix ASIC3 SD... |
848 849 |
mem_sdio->start, ASIC3_SD_CONFIG_SIZE >> asic->bus_shift); |
64e8867ba mfd: tmio_mmc har... |
850 851 852 853 854 855 |
if (!asic->tmio_cnf) { ret = -ENOMEM; dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG "); goto out; } |
09f05ce85 mfd: asic3: enabl... |
856 857 |
asic3_mmc_resources[0].start >>= asic->bus_shift; asic3_mmc_resources[0].end >>= asic->bus_shift; |
09f05ce85 mfd: asic3: enabl... |
858 |
|
9461f65a8 mfd: asic3: enabl... |
859 860 |
ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_ds1wm, 1, mem, asic->irq_base); |
09f05ce85 mfd: asic3: enabl... |
861 862 |
if (ret < 0) goto out; |
13ca4f661 mfd: Add ASIC3 LE... |
863 |
if (mem_sdio && (irq >= 0)) { |
09f05ce85 mfd: asic3: enabl... |
864 865 |
ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_mmc, 1, mem_sdio, irq); |
13ca4f661 mfd: Add ASIC3 LE... |
866 867 868 869 870 871 872 873 874 875 876 877 878 879 |
if (ret < 0) goto out; } if (pdata->leds) { int i; for (i = 0; i < ASIC3_NUM_LEDS; ++i) { asic3_cell_leds[i].platform_data = &pdata->leds[i]; asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]); } ret = mfd_add_devices(&pdev->dev, 0, asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0); } |
9461f65a8 mfd: asic3: enabl... |
880 |
|
09f05ce85 mfd: asic3: enabl... |
881 |
out: |
9461f65a8 mfd: asic3: enabl... |
882 883 884 885 886 |
return ret; } static void asic3_mfd_remove(struct platform_device *pdev) { |
64e8867ba mfd: tmio_mmc har... |
887 |
struct asic3 *asic = platform_get_drvdata(pdev); |
9461f65a8 mfd: asic3: enabl... |
888 |
mfd_remove_devices(&pdev->dev); |
64e8867ba mfd: tmio_mmc har... |
889 |
iounmap(asic->tmio_cnf); |
9461f65a8 mfd: asic3: enabl... |
890 |
} |
fa9ff4b18 ASIC3 driver |
891 |
/* Core */ |
065032f61 mfd: move asic3 p... |
892 |
static int __init asic3_probe(struct platform_device *pdev) |
fa9ff4b18 ASIC3 driver |
893 894 895 896 897 |
{ struct asic3_platform_data *pdata = pdev->dev.platform_data; struct asic3 *asic; struct resource *mem; unsigned long clksel; |
6f2384c4b mfd: asic3 gpioli... |
898 |
int ret = 0; |
fa9ff4b18 ASIC3 driver |
899 900 |
asic = kzalloc(sizeof(struct asic3), GFP_KERNEL); |
6f2384c4b mfd: asic3 gpioli... |
901 902 903 |
if (asic == NULL) { printk(KERN_ERR "kzalloc failed "); |
fa9ff4b18 ASIC3 driver |
904 |
return -ENOMEM; |
6f2384c4b mfd: asic3 gpioli... |
905 |
} |
fa9ff4b18 ASIC3 driver |
906 907 908 909 910 911 912 913 |
spin_lock_init(&asic->lock); platform_set_drvdata(pdev, asic); asic->dev = &pdev->dev; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { ret = -ENOMEM; |
24f4f2eef mfd: use dev_* ma... |
914 915 |
dev_err(asic->dev, "no MEM resource "); |
6f2384c4b mfd: asic3 gpioli... |
916 |
goto out_free; |
fa9ff4b18 ASIC3 driver |
917 |
} |
be584bd5a mfd: asic3: use r... |
918 |
asic->mapping = ioremap(mem->start, resource_size(mem)); |
fa9ff4b18 ASIC3 driver |
919 920 |
if (!asic->mapping) { ret = -ENOMEM; |
24f4f2eef mfd: use dev_* ma... |
921 922 |
dev_err(asic->dev, "Couldn't ioremap "); |
6f2384c4b mfd: asic3 gpioli... |
923 |
goto out_free; |
fa9ff4b18 ASIC3 driver |
924 925 926 |
} asic->irq_base = pdata->irq_base; |
99cdb0c8c mfd: let asic3 us... |
927 |
/* calculate bus shift from mem resource */ |
be584bd5a mfd: asic3: use r... |
928 |
asic->bus_shift = 2 - (resource_size(mem) >> 12); |
fa9ff4b18 ASIC3 driver |
929 930 931 932 933 934 |
clksel = 0; asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel); ret = asic3_irq_probe(pdev); if (ret < 0) { |
24f4f2eef mfd: use dev_* ma... |
935 936 |
dev_err(asic->dev, "Couldn't probe IRQs "); |
6f2384c4b mfd: asic3 gpioli... |
937 938 |
goto out_unmap; } |
d8e4a88b7 mfd: Define asic3... |
939 |
asic->gpio.label = "asic3"; |
6f2384c4b mfd: asic3 gpioli... |
940 941 942 943 944 945 |
asic->gpio.base = pdata->gpio_base; asic->gpio.ngpio = ASIC3_NUM_GPIOS; asic->gpio.get = asic3_gpio_get; asic->gpio.set = asic3_gpio_set; asic->gpio.direction_input = asic3_gpio_direction_input; asic->gpio.direction_output = asic3_gpio_direction_output; |
3b26bf172 mfd: New asic3 gp... |
946 947 948 |
ret = asic3_gpio_probe(pdev, pdata->gpio_config, pdata->gpio_config_num); |
6f2384c4b mfd: asic3 gpioli... |
949 |
if (ret < 0) { |
24f4f2eef mfd: use dev_* ma... |
950 951 |
dev_err(asic->dev, "GPIO probe failed "); |
6f2384c4b mfd: asic3 gpioli... |
952 |
goto out_irq; |
fa9ff4b18 ASIC3 driver |
953 |
} |
fa9ff4b18 ASIC3 driver |
954 |
|
e956a2a87 mfd: asic3: add c... |
955 956 957 958 |
/* Making a per-device copy is only needed for the * theoretical case of multiple ASIC3s on one board: */ memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init)); |
13ca4f661 mfd: Add ASIC3 LE... |
959 |
asic3_mfd_probe(pdev, pdata, mem); |
9461f65a8 mfd: asic3: enabl... |
960 |
|
24f4f2eef mfd: use dev_* ma... |
961 962 |
dev_info(asic->dev, "ASIC3 Core driver "); |
fa9ff4b18 ASIC3 driver |
963 964 |
return 0; |
6f2384c4b mfd: asic3 gpioli... |
965 966 967 968 |
out_irq: asic3_irq_remove(pdev); out_unmap: |
fa9ff4b18 ASIC3 driver |
969 |
iounmap(asic->mapping); |
6f2384c4b mfd: asic3 gpioli... |
970 971 |
out_free: |
fa9ff4b18 ASIC3 driver |
972 973 974 975 |
kfree(asic); return ret; } |
1e3edaf6c mfd: Move asic3_r... |
976 |
static int __devexit asic3_remove(struct platform_device *pdev) |
fa9ff4b18 ASIC3 driver |
977 |
{ |
6f2384c4b mfd: asic3 gpioli... |
978 |
int ret; |
fa9ff4b18 ASIC3 driver |
979 |
struct asic3 *asic = platform_get_drvdata(pdev); |
9461f65a8 mfd: asic3: enabl... |
980 |
asic3_mfd_remove(pdev); |
6f2384c4b mfd: asic3 gpioli... |
981 982 983 |
ret = asic3_gpio_remove(pdev); if (ret < 0) return ret; |
fa9ff4b18 ASIC3 driver |
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 |
asic3_irq_remove(pdev); asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0); iounmap(asic->mapping); kfree(asic); return 0; } static void asic3_shutdown(struct platform_device *pdev) { } static struct platform_driver asic3_device_driver = { .driver = { .name = "asic3", }, |
fa9ff4b18 ASIC3 driver |
1003 1004 1005 1006 1007 1008 1009 |
.remove = __devexit_p(asic3_remove), .shutdown = asic3_shutdown, }; static int __init asic3_init(void) { int retval = 0; |
065032f61 mfd: move asic3 p... |
1010 |
retval = platform_driver_probe(&asic3_device_driver, asic3_probe); |
fa9ff4b18 ASIC3 driver |
1011 1012 1013 1014 |
return retval; } subsys_initcall(asic3_init); |