asic3.c 23.8 KB
Newer Older
S
Samuel Ortiz 已提交
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
S
Samuel Ortiz 已提交
12
 * Copyright 2007-2008 OpenedHand Ltd.
S
Samuel Ortiz 已提交
13 14 15 16 17 18 19
 *
 * Authors: Phil Blundell <pb@handhelds.org>,
 *	    Samuel Ortiz <sameo@openedhand.com>
 *
 */

#include <linux/kernel.h>
P
Philipp Zabel 已提交
20
#include <linux/delay.h>
S
Samuel Ortiz 已提交
21
#include <linux/irq.h>
S
Samuel Ortiz 已提交
22
#include <linux/gpio.h>
S
Samuel Ortiz 已提交
23
#include <linux/io.h>
24
#include <linux/slab.h>
S
Samuel Ortiz 已提交
25 26 27 28
#include <linux/spinlock.h>
#include <linux/platform_device.h>

#include <linux/mfd/asic3.h>
P
Philipp Zabel 已提交
29 30
#include <linux/mfd/core.h>
#include <linux/mfd/ds1wm.h>
P
Philipp Zabel 已提交
31
#include <linux/mfd/tmio.h>
S
Samuel Ortiz 已提交
32

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 59
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,			\
	}

60
static struct asic3_clk asic3_clk_init[] __initdata = {
61 62 63 64 65 66 67 68 69 70 71 72 73 74
	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),
};

S
Samuel Ortiz 已提交
75 76 77 78 79 80 81 82 83
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;
84
	void __iomem *tmio_cnf;
85 86

	struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)];
S
Samuel Ortiz 已提交
87 88 89 90
};

static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);

S
Samuel Ortiz 已提交
91 92 93
static inline void asic3_write_register(struct asic3 *asic,
				 unsigned int reg, u32 value)
{
94
	iowrite16(value, asic->mapping +
S
Samuel Ortiz 已提交
95 96 97 98 99 100
		  (reg >> asic->bus_shift));
}

static inline u32 asic3_read_register(struct asic3 *asic,
			       unsigned int reg)
{
101
	return ioread16(asic->mapping +
S
Samuel Ortiz 已提交
102 103 104
			(reg >> asic->bus_shift));
}

105
static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
106 107 108 109 110 111 112 113 114 115 116 117 118 119
{
	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);
}

S
Samuel Ortiz 已提交
120 121
/* IRQs */
#define MAX_ASIC_ISR_LOOPS    20
122 123
#define ASIC3_GPIO_BASE_INCR \
	(ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE)
S
Samuel Ortiz 已提交
124 125 126 127 128 129 130 131 132

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,
133
				   base + ASIC3_GPIO_EDGE_TRIGGER);
S
Samuel Ortiz 已提交
134 135
	edge ^= bit;
	asic3_write_register(asic,
136
			     base + ASIC3_GPIO_EDGE_TRIGGER, edge);
S
Samuel Ortiz 已提交
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
	spin_unlock_irqrestore(&asic->lock, flags);
}

static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
{
	int iter, i;
	unsigned long flags;
	struct asic3 *asic;

	desc->chip->ack(irq);

	asic = desc->handler_data;

	for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) {
		u32 status;
		int bank;

		spin_lock_irqsave(&asic->lock, flags);
		status = asic3_read_register(asic,
156
					     ASIC3_OFFSET(INTR, P_INT_STAT));
S
Samuel Ortiz 已提交
157 158 159 160 161 162 163 164 165 166 167
		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;

168 169
				base = ASIC3_GPIO_A_BASE
				       + bank * ASIC3_GPIO_BASE_INCR;
S
Samuel Ortiz 已提交
170 171 172 173

				spin_lock_irqsave(&asic->lock, flags);
				istat = asic3_read_register(asic,
							    base +
174
							    ASIC3_GPIO_INT_STATUS);
S
Samuel Ortiz 已提交
175 176 177
				/* Clearing IntStatus */
				asic3_write_register(asic,
						     base +
178
						     ASIC3_GPIO_INT_STATUS, 0);
S
Samuel Ortiz 已提交
179 180 181 182 183 184 185 186 187 188 189 190
				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;
191
					desc = irq_to_desc(irqnr);
S
Samuel Ortiz 已提交
192 193 194 195 196 197 198 199 200 201 202 203
					desc->handle_irq(irqnr, desc);
					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 */
			if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) {
204
				desc = irq_to_desc(asic->irq_base + i);
S
Samuel Ortiz 已提交
205 206 207 208 209 210 211
				desc->handle_irq(asic->irq_base + i,
						 desc);
			}
		}
	}

	if (iter >= MAX_ASIC_ISR_LOOPS)
212
		dev_err(asic->dev, "interrupt processing overrun\n");
S
Samuel Ortiz 已提交
213 214 215 216 217 218 219 220
}

static inline int asic3_irq_to_bank(struct asic3 *asic, int irq)
{
	int n;

	n = (irq - asic->irq_base) >> 4;

221
	return (n * (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE));
S
Samuel Ortiz 已提交
222 223 224 225 226 227 228
}

static inline int asic3_irq_to_index(struct asic3 *asic, int irq)
{
	return (irq - asic->irq_base) & 0xf;
}

M
Mark Brown 已提交
229
static void asic3_mask_gpio_irq(struct irq_data *data)
S
Samuel Ortiz 已提交
230
{
M
Mark Brown 已提交
231
	struct asic3 *asic = irq_data_get_irq_chip_data(data);
S
Samuel Ortiz 已提交
232 233 234
	u32 val, bank, index;
	unsigned long flags;

M
Mark Brown 已提交
235 236
	bank = asic3_irq_to_bank(asic, data->irq);
	index = asic3_irq_to_index(asic, data->irq);
S
Samuel Ortiz 已提交
237 238

	spin_lock_irqsave(&asic->lock, flags);
239
	val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
S
Samuel Ortiz 已提交
240
	val |= 1 << index;
241
	asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val);
S
Samuel Ortiz 已提交
242 243 244
	spin_unlock_irqrestore(&asic->lock, flags);
}

M
Mark Brown 已提交
245
static void asic3_mask_irq(struct irq_data *data)
S
Samuel Ortiz 已提交
246
{
M
Mark Brown 已提交
247
	struct asic3 *asic = irq_data_get_irq_chip_data(data);
S
Samuel Ortiz 已提交
248 249 250 251 252
	int regval;
	unsigned long flags;

	spin_lock_irqsave(&asic->lock, flags);
	regval = asic3_read_register(asic,
253 254
				     ASIC3_INTR_BASE +
				     ASIC3_INTR_INT_MASK);
S
Samuel Ortiz 已提交
255 256

	regval &= ~(ASIC3_INTMASK_MASK0 <<
M
Mark Brown 已提交
257
		    (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
S
Samuel Ortiz 已提交
258 259

	asic3_write_register(asic,
260 261
			     ASIC3_INTR_BASE +
			     ASIC3_INTR_INT_MASK,
S
Samuel Ortiz 已提交
262 263 264 265
			     regval);
	spin_unlock_irqrestore(&asic->lock, flags);
}

M
Mark Brown 已提交
266
static void asic3_unmask_gpio_irq(struct irq_data *data)
S
Samuel Ortiz 已提交
267
{
M
Mark Brown 已提交
268
	struct asic3 *asic = irq_data_get_irq_chip_data(data);
S
Samuel Ortiz 已提交
269 270 271
	u32 val, bank, index;
	unsigned long flags;

M
Mark Brown 已提交
272 273
	bank = asic3_irq_to_bank(asic, data->irq);
	index = asic3_irq_to_index(asic, data->irq);
S
Samuel Ortiz 已提交
274 275

	spin_lock_irqsave(&asic->lock, flags);
276
	val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
S
Samuel Ortiz 已提交
277
	val &= ~(1 << index);
278
	asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val);
S
Samuel Ortiz 已提交
279 280 281
	spin_unlock_irqrestore(&asic->lock, flags);
}

M
Mark Brown 已提交
282
static void asic3_unmask_irq(struct irq_data *data)
S
Samuel Ortiz 已提交
283
{
M
Mark Brown 已提交
284
	struct asic3 *asic = irq_data_get_irq_chip_data(data);
S
Samuel Ortiz 已提交
285 286 287 288 289
	int regval;
	unsigned long flags;

	spin_lock_irqsave(&asic->lock, flags);
	regval = asic3_read_register(asic,
290 291
				     ASIC3_INTR_BASE +
				     ASIC3_INTR_INT_MASK);
S
Samuel Ortiz 已提交
292 293

	regval |= (ASIC3_INTMASK_MASK0 <<
M
Mark Brown 已提交
294
		   (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
S
Samuel Ortiz 已提交
295 296

	asic3_write_register(asic,
297 298
			     ASIC3_INTR_BASE +
			     ASIC3_INTR_INT_MASK,
S
Samuel Ortiz 已提交
299 300 301 302
			     regval);
	spin_unlock_irqrestore(&asic->lock, flags);
}

M
Mark Brown 已提交
303
static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
S
Samuel Ortiz 已提交
304
{
M
Mark Brown 已提交
305
	struct asic3 *asic = irq_data_get_irq_chip_data(data);
S
Samuel Ortiz 已提交
306 307 308 309
	u32 bank, index;
	u16 trigger, level, edge, bit;
	unsigned long flags;

M
Mark Brown 已提交
310 311
	bank = asic3_irq_to_bank(asic, data->irq);
	index = asic3_irq_to_index(asic, data->irq);
S
Samuel Ortiz 已提交
312 313 314 315
	bit = 1<<index;

	spin_lock_irqsave(&asic->lock, flags);
	level = asic3_read_register(asic,
316
				    bank + ASIC3_GPIO_LEVEL_TRIGGER);
S
Samuel Ortiz 已提交
317
	edge = asic3_read_register(asic,
318
				   bank + ASIC3_GPIO_EDGE_TRIGGER);
S
Samuel Ortiz 已提交
319
	trigger = asic3_read_register(asic,
320
				      bank + ASIC3_GPIO_TRIGGER_TYPE);
M
Mark Brown 已提交
321
	asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit;
S
Samuel Ortiz 已提交
322

323
	if (type == IRQ_TYPE_EDGE_RISING) {
S
Samuel Ortiz 已提交
324 325
		trigger |= bit;
		edge |= bit;
326
	} else if (type == IRQ_TYPE_EDGE_FALLING) {
S
Samuel Ortiz 已提交
327 328
		trigger |= bit;
		edge &= ~bit;
329
	} else if (type == IRQ_TYPE_EDGE_BOTH) {
S
Samuel Ortiz 已提交
330
		trigger |= bit;
M
Mark Brown 已提交
331
		if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base))
S
Samuel Ortiz 已提交
332 333 334
			edge &= ~bit;
		else
			edge |= bit;
M
Mark Brown 已提交
335
		asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit;
336
	} else if (type == IRQ_TYPE_LEVEL_LOW) {
S
Samuel Ortiz 已提交
337 338
		trigger &= ~bit;
		level &= ~bit;
339
	} else if (type == IRQ_TYPE_LEVEL_HIGH) {
S
Samuel Ortiz 已提交
340 341 342 343
		trigger &= ~bit;
		level |= bit;
	} else {
		/*
344
		 * if type == IRQ_TYPE_NONE, we should mask interrupts, but
S
Samuel Ortiz 已提交
345 346 347
		 * be careful to not unmask them if mask was also called.
		 * Probably need internal state for mask.
		 */
348
		dev_notice(asic->dev, "irq type not changed\n");
S
Samuel Ortiz 已提交
349
	}
350
	asic3_write_register(asic, bank + ASIC3_GPIO_LEVEL_TRIGGER,
S
Samuel Ortiz 已提交
351
			     level);
352
	asic3_write_register(asic, bank + ASIC3_GPIO_EDGE_TRIGGER,
S
Samuel Ortiz 已提交
353
			     edge);
354
	asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE,
S
Samuel Ortiz 已提交
355 356 357 358 359 360 361
			     trigger);
	spin_unlock_irqrestore(&asic->lock, flags);
	return 0;
}

static struct irq_chip asic3_gpio_irq_chip = {
	.name		= "ASIC3-GPIO",
M
Mark Brown 已提交
362 363 364 365
	.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,
S
Samuel Ortiz 已提交
366 367 368 369
};

static struct irq_chip asic3_irq_chip = {
	.name		= "ASIC3",
M
Mark Brown 已提交
370 371 372
	.irq_ack	= asic3_mask_irq,
	.irq_mask	= asic3_mask_irq,
	.irq_unmask	= asic3_unmask_irq,
S
Samuel Ortiz 已提交
373 374
};

375
static int __init asic3_irq_probe(struct platform_device *pdev)
S
Samuel Ortiz 已提交
376 377 378 379
{
	struct asic3 *asic = platform_get_drvdata(pdev);
	unsigned long clksel = 0;
	unsigned int irq, irq_base;
380
	int ret;
S
Samuel Ortiz 已提交
381

382 383 384 385
	ret = platform_get_irq(pdev, 0);
	if (ret < 0)
		return ret;
	asic->irq_nr = ret;
S
Samuel Ortiz 已提交
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404

	/* 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)
			set_irq_chip(irq, &asic3_gpio_irq_chip);
		else
			set_irq_chip(irq, &asic3_irq_chip);

		set_irq_chip_data(irq, asic);
		set_irq_handler(irq, handle_level_irq);
		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
	}

405
	asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK),
S
Samuel Ortiz 已提交
406 407 408
			     ASIC3_INTMASK_GINTMASK);

	set_irq_chained_handler(asic->irq_nr, asic3_irq_demux);
409
	set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING);
S
Samuel Ortiz 已提交
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
	set_irq_data(asic->irq_nr, asic);

	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);
		set_irq_handler(irq, NULL);
		set_irq_chip(irq, NULL);
		set_irq_chip_data(irq, NULL);
	}
	set_irq_chained_handler(asic->irq_nr, NULL);
}

/* GPIOs */
S
Samuel Ortiz 已提交
432 433 434 435 436 437 438 439 440 441 442
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);

443
	if (gpio_base > ASIC3_GPIO_D_BASE) {
444 445
		dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n",
			gpio_base, offset);
S
Samuel Ortiz 已提交
446 447 448 449 450
		return -EINVAL;
	}

	spin_lock_irqsave(&asic->lock, flags);

451
	out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION);
S
Samuel Ortiz 已提交
452 453 454 455 456 457 458

	/* Input is 0, Output is 1 */
	if (out)
		out_reg |= mask;
	else
		out_reg &= ~mask;

459
	asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg);
S
Samuel Ortiz 已提交
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488

	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);

489
	if (gpio_base > ASIC3_GPIO_D_BASE) {
490 491
		dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n",
			gpio_base, offset);
S
Samuel Ortiz 已提交
492 493 494
		return -EINVAL;
	}

495
	return asic3_read_register(asic, gpio_base + ASIC3_GPIO_STATUS) & mask;
S
Samuel Ortiz 已提交
496 497 498 499 500 501 502 503 504 505 506 507 508
}

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);

509
	if (gpio_base > ASIC3_GPIO_D_BASE) {
510 511
		dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n",
			gpio_base, offset);
S
Samuel Ortiz 已提交
512 513 514 515 516 517 518
		return;
	}

	mask = ASIC3_GPIO_TO_MASK(offset);

	spin_lock_irqsave(&asic->lock, flags);

519
	out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT);
S
Samuel Ortiz 已提交
520 521 522 523 524 525

	if (value)
		out_reg |= mask;
	else
		out_reg &= ~mask;

526
	asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg);
S
Samuel Ortiz 已提交
527 528 529 530 531 532

	spin_unlock_irqrestore(&asic->lock, flags);

	return;
}

533 534
static __init int asic3_gpio_probe(struct platform_device *pdev,
				   u16 *gpio_config, int num)
S
Samuel Ortiz 已提交
535 536
{
	struct asic3 *asic = platform_get_drvdata(pdev);
537 538 539 540
	u16 alt_reg[ASIC3_NUM_GPIO_BANKS];
	u16 out_reg[ASIC3_NUM_GPIO_BANKS];
	u16 dir_reg[ASIC3_NUM_GPIO_BANKS];
	int i;
S
Samuel Ortiz 已提交
541

R
Russell King 已提交
542 543 544
	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));
545 546

	/* Enable all GPIOs */
547 548 549 550
	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);
S
Samuel Ortiz 已提交
551

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
	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) +
572
				     ASIC3_GPIO_DIRECTION,
573 574
				     dir_reg[i]);
		asic3_write_register(asic,
575
				     ASIC3_BANK_TO_BASE(i) + ASIC3_GPIO_OUT,
576 577 578
				     out_reg[i]);
		asic3_write_register(asic,
				     ASIC3_BANK_TO_BASE(i) +
579
				     ASIC3_GPIO_ALT_FUNCTION,
580
				     alt_reg[i]);
S
Samuel Ortiz 已提交
581 582
	}

S
Samuel Ortiz 已提交
583
	return gpiochip_add(&asic->gpio);
S
Samuel Ortiz 已提交
584 585
}

S
Samuel Ortiz 已提交
586
static int asic3_gpio_remove(struct platform_device *pdev)
S
Samuel Ortiz 已提交
587
{
S
Samuel Ortiz 已提交
588 589 590
	struct asic3 *asic = platform_get_drvdata(pdev);

	return gpiochip_remove(&asic->gpio);
S
Samuel Ortiz 已提交
591 592
}

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
static int asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
{
	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);

	return 0;
}

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);
}
S
Samuel Ortiz 已提交
624

P
Philipp Zabel 已提交
625 626 627 628 629 630 631 632 633 634 635 636 637
/* MFD cells (SPI, PWM, LED, DS1WM, MMC) */
static struct ds1wm_driver_data ds1wm_pdata = {
	.active_high = 1,
};

static struct resource ds1wm_resources[] = {
	{
		.start = ASIC3_OWM_BASE,
		.end   = ASIC3_OWM_BASE + 0x13,
		.flags = IORESOURCE_MEM,
	},
	{
		.start = ASIC3_IRQ_OWM,
638
		.end   = ASIC3_IRQ_OWM,
P
Philipp Zabel 已提交
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
		.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,
	.driver_data   = &ds1wm_pdata,
	.num_resources = ARRAY_SIZE(ds1wm_resources),
	.resources     = ds1wm_resources,
};

690 691 692 693 694 695 696 697 698 699 700 701 702 703
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);
}

P
Philipp Zabel 已提交
704
static struct tmio_mmc_data asic3_mmc_data = {
705 706 707
	.hclk           = 24576000,
	.set_pwr        = asic3_mmc_pwr,
	.set_clk_div    = asic3_mmc_clk_div,
P
Philipp Zabel 已提交
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
};

static struct resource asic3_mmc_resources[] = {
	{
		.start = ASIC3_SD_CTRL_BASE,
		.end   = ASIC3_SD_CTRL_BASE + 0x3ff,
		.flags = IORESOURCE_MEM,
	},
	{
		.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);

759 760 761 762
	/* 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);

P
Philipp Zabel 已提交
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
	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,
	.driver_data   = &asic3_mmc_data,
	.num_resources = ARRAY_SIZE(asic3_mmc_resources),
	.resources     = asic3_mmc_resources,
};

P
Philipp Zabel 已提交
791 792 793 794
static int __init asic3_mfd_probe(struct platform_device *pdev,
				  struct resource *mem)
{
	struct asic3 *asic = platform_get_drvdata(pdev);
P
Philipp Zabel 已提交
795 796 797 798 799 800 801 802 803 804
	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\n");

	irq = platform_get_irq(pdev, 1);
	if (irq < 0)
		dev_dbg(asic->dev, "no SDIO IRQ resource\n");
P
Philipp Zabel 已提交
805 806 807 808 809 810 811 812 813 814 815

	/* 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;

	asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm;
	asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);

P
Philipp Zabel 已提交
816
	/* MMC */
817 818 819 820 821 822 823
	asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
				 mem_sdio->start, 0x400 >> asic->bus_shift);
	if (!asic->tmio_cnf) {
		ret = -ENOMEM;
		dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
		goto out;
	}
P
Philipp Zabel 已提交
824 825 826 827 828 829
	asic3_mmc_resources[0].start >>= asic->bus_shift;
	asic3_mmc_resources[0].end   >>= asic->bus_shift;

	asic3_cell_mmc.platform_data = &asic3_cell_mmc;
	asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc);

P
Philipp Zabel 已提交
830 831
	ret = mfd_add_devices(&pdev->dev, pdev->id,
			&asic3_cell_ds1wm, 1, mem, asic->irq_base);
P
Philipp Zabel 已提交
832 833 834 835 836 837
	if (ret < 0)
		goto out;

	if (mem_sdio && (irq >= 0))
		ret = mfd_add_devices(&pdev->dev, pdev->id,
			&asic3_cell_mmc, 1, mem_sdio, irq);
P
Philipp Zabel 已提交
838

P
Philipp Zabel 已提交
839
 out:
P
Philipp Zabel 已提交
840 841 842 843 844
	return ret;
}

static void asic3_mfd_remove(struct platform_device *pdev)
{
845 846
	struct asic3 *asic = platform_get_drvdata(pdev);

P
Philipp Zabel 已提交
847
	mfd_remove_devices(&pdev->dev);
848
	iounmap(asic->tmio_cnf);
P
Philipp Zabel 已提交
849 850
}

S
Samuel Ortiz 已提交
851
/* Core */
852
static int __init asic3_probe(struct platform_device *pdev)
S
Samuel Ortiz 已提交
853 854 855 856 857
{
	struct asic3_platform_data *pdata = pdev->dev.platform_data;
	struct asic3 *asic;
	struct resource *mem;
	unsigned long clksel;
S
Samuel Ortiz 已提交
858
	int ret = 0;
S
Samuel Ortiz 已提交
859 860

	asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
S
Samuel Ortiz 已提交
861 862
	if (asic == NULL) {
		printk(KERN_ERR "kzalloc failed\n");
S
Samuel Ortiz 已提交
863
		return -ENOMEM;
S
Samuel Ortiz 已提交
864
	}
S
Samuel Ortiz 已提交
865 866 867 868 869 870 871 872

	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;
873
		dev_err(asic->dev, "no MEM resource\n");
S
Samuel Ortiz 已提交
874
		goto out_free;
S
Samuel Ortiz 已提交
875 876
	}

877
	asic->mapping = ioremap(mem->start, resource_size(mem));
S
Samuel Ortiz 已提交
878 879
	if (!asic->mapping) {
		ret = -ENOMEM;
880
		dev_err(asic->dev, "Couldn't ioremap\n");
S
Samuel Ortiz 已提交
881
		goto out_free;
S
Samuel Ortiz 已提交
882 883 884 885
	}

	asic->irq_base = pdata->irq_base;

886
	/* calculate bus shift from mem resource */
887
	asic->bus_shift = 2 - (resource_size(mem) >> 12);
S
Samuel Ortiz 已提交
888 889 890 891 892 893

	clksel = 0;
	asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel);

	ret = asic3_irq_probe(pdev);
	if (ret < 0) {
894
		dev_err(asic->dev, "Couldn't probe IRQs\n");
S
Samuel Ortiz 已提交
895 896 897 898 899 900 901 902 903 904
		goto out_unmap;
	}

	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;

905 906 907
	ret = asic3_gpio_probe(pdev,
			       pdata->gpio_config,
			       pdata->gpio_config_num);
S
Samuel Ortiz 已提交
908
	if (ret < 0) {
909
		dev_err(asic->dev, "GPIO probe failed\n");
S
Samuel Ortiz 已提交
910
		goto out_irq;
S
Samuel Ortiz 已提交
911 912
	}

913 914 915 916 917
	/* 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));

P
Philipp Zabel 已提交
918 919
	asic3_mfd_probe(pdev, mem);

920
	dev_info(asic->dev, "ASIC3 Core driver\n");
S
Samuel Ortiz 已提交
921 922 923

	return 0;

S
Samuel Ortiz 已提交
924 925 926 927
 out_irq:
	asic3_irq_remove(pdev);

 out_unmap:
S
Samuel Ortiz 已提交
928
	iounmap(asic->mapping);
S
Samuel Ortiz 已提交
929 930

 out_free:
S
Samuel Ortiz 已提交
931 932 933 934 935
	kfree(asic);

	return ret;
}

936
static int __devexit asic3_remove(struct platform_device *pdev)
S
Samuel Ortiz 已提交
937
{
S
Samuel Ortiz 已提交
938
	int ret;
S
Samuel Ortiz 已提交
939 940
	struct asic3 *asic = platform_get_drvdata(pdev);

P
Philipp Zabel 已提交
941 942
	asic3_mfd_remove(pdev);

S
Samuel Ortiz 已提交
943 944 945
	ret = asic3_gpio_remove(pdev);
	if (ret < 0)
		return ret;
S
Samuel Ortiz 已提交
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
	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",
	},
	.remove		= __devexit_p(asic3_remove),
	.shutdown	= asic3_shutdown,
};

static int __init asic3_init(void)
{
	int retval = 0;
972
	retval = platform_driver_probe(&asic3_device_driver, asic3_probe);
S
Samuel Ortiz 已提交
973 974 975 976
	return retval;
}

subsys_initcall(asic3_init);