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