gpio-aspeed.c 30.5 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
Joel Stanley's avatar
Joel Stanley committed
2 3 4 5 6 7
/*
 * Copyright 2015 IBM Corp.
 *
 * Joel Stanley <joel@jms.id.au>
 */

8 9 10
#include <asm/div64.h>
#include <linux/clk.h>
#include <linux/gpio/driver.h>
11
#include <linux/gpio/aspeed.h>
12
#include <linux/hashtable.h>
Joel Stanley's avatar
Joel Stanley committed
13 14
#include <linux/init.h>
#include <linux/io.h>
15 16
#include <linux/kernel.h>
#include <linux/module.h>
Joel Stanley's avatar
Joel Stanley committed
17
#include <linux/pinctrl/consumer.h>
18 19 20
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/string.h>
Joel Stanley's avatar
Joel Stanley committed
21

22 23 24 25 26 27 28 29 30
/*
 * These two headers aren't meant to be used by GPIO drivers. We need
 * them in order to access gpio_chip_hwgpio() which we need to implement
 * the aspeed specific API which allows the coprocessor to request
 * access to some GPIOs and to arbitrate between coprocessor and ARM.
 */
#include <linux/gpio/consumer.h>
#include "gpiolib.h"

31 32 33 34 35 36 37 38 39 40 41
struct aspeed_bank_props {
	unsigned int bank;
	u32 input;
	u32 output;
};

struct aspeed_gpio_config {
	unsigned int nr_gpios;
	const struct aspeed_bank_props *props;
};

42 43 44 45 46 47 48 49 50 51 52
/*
 * @offset_timer: Maps an offset to an @timer_users index, or zero if disabled
 * @timer_users: Tracks the number of users for each timer
 *
 * The @timer_users has four elements but the first element is unused. This is
 * to simplify accounting and indexing, as a zero value in @offset_timer
 * represents disabled debouncing for the GPIO. Any other value for an element
 * of @offset_timer is used as an index into @timer_users. This behaviour of
 * the zero value aligns with the behaviour of zero built from the timer
 * configuration registers (i.e. debouncing is disabled).
 */
Joel Stanley's avatar
Joel Stanley committed
53 54 55 56 57
struct aspeed_gpio {
	struct gpio_chip chip;
	spinlock_t lock;
	void __iomem *base;
	int irq;
58
	const struct aspeed_gpio_config *config;
59 60 61 62

	u8 *offset_timer;
	unsigned int timer_users[4];
	struct clk *clk;
63 64

	u32 *dcache;
65
	u8 *cf_copro_bankmap;
Joel Stanley's avatar
Joel Stanley committed
66 67 68
};

struct aspeed_gpio_bank {
69 70 71 72
	uint16_t	val_regs;	/* +0: Rd: read input value, Wr: set write latch
					 * +4: Rd/Wr: Direction (0=in, 1=out)
					 */
	uint16_t	rdata_reg;	/*     Rd: read write latch, Wr: <none>  */
Joel Stanley's avatar
Joel Stanley committed
73
	uint16_t	irq_regs;
74
	uint16_t	debounce_regs;
75
	uint16_t	tolerance_regs;
76
	uint16_t	cmdsrc_regs;
77
	const char	names[4][3];
Joel Stanley's avatar
Joel Stanley committed
78 79
};

80 81 82 83 84 85 86 87 88 89 90
/*
 * Note: The "value" register returns the input value sampled on the
 *       line even when the GPIO is configured as an output. Since
 *       that input goes through synchronizers, writing, then reading
 *       back may not return the written value right away.
 *
 *       The "rdata" register returns the content of the write latch
 *       and thus can be used to read back what was last written
 *       reliably.
 */

91 92
static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 };

93 94 95
static const struct aspeed_gpio_copro_ops *copro_ops;
static void *copro_data;

Joel Stanley's avatar
Joel Stanley committed
96 97 98
static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {
	{
		.val_regs = 0x0000,
99
		.rdata_reg = 0x00c0,
Joel Stanley's avatar
Joel Stanley committed
100
		.irq_regs = 0x0008,
101
		.debounce_regs = 0x0040,
102
		.tolerance_regs = 0x001c,
103
		.cmdsrc_regs = 0x0060,
104
		.names = { "A", "B", "C", "D" },
Joel Stanley's avatar
Joel Stanley committed
105 106 107
	},
	{
		.val_regs = 0x0020,
108
		.rdata_reg = 0x00c4,
Joel Stanley's avatar
Joel Stanley committed
109
		.irq_regs = 0x0028,
110
		.debounce_regs = 0x0048,
111
		.tolerance_regs = 0x003c,
112
		.cmdsrc_regs = 0x0068,
113
		.names = { "E", "F", "G", "H" },
Joel Stanley's avatar
Joel Stanley committed
114 115 116
	},
	{
		.val_regs = 0x0070,
117
		.rdata_reg = 0x00c8,
Joel Stanley's avatar
Joel Stanley committed
118
		.irq_regs = 0x0098,
119
		.debounce_regs = 0x00b0,
120
		.tolerance_regs = 0x00ac,
121
		.cmdsrc_regs = 0x0090,
122
		.names = { "I", "J", "K", "L" },
Joel Stanley's avatar
Joel Stanley committed
123 124 125
	},
	{
		.val_regs = 0x0078,
126
		.rdata_reg = 0x00cc,
Joel Stanley's avatar
Joel Stanley committed
127
		.irq_regs = 0x00e8,
128
		.debounce_regs = 0x0100,
129
		.tolerance_regs = 0x00fc,
130
		.cmdsrc_regs = 0x00e0,
131
		.names = { "M", "N", "O", "P" },
Joel Stanley's avatar
Joel Stanley committed
132 133 134
	},
	{
		.val_regs = 0x0080,
135
		.rdata_reg = 0x00d0,
Joel Stanley's avatar
Joel Stanley committed
136
		.irq_regs = 0x0118,
137
		.debounce_regs = 0x0130,
138
		.tolerance_regs = 0x012c,
139
		.cmdsrc_regs = 0x0110,
140
		.names = { "Q", "R", "S", "T" },
Joel Stanley's avatar
Joel Stanley committed
141 142 143
	},
	{
		.val_regs = 0x0088,
144
		.rdata_reg = 0x00d4,
Joel Stanley's avatar
Joel Stanley committed
145
		.irq_regs = 0x0148,
146
		.debounce_regs = 0x0160,
147
		.tolerance_regs = 0x015c,
148
		.cmdsrc_regs = 0x0140,
149
		.names = { "U", "V", "W", "X" },
Joel Stanley's avatar
Joel Stanley committed
150
	},
151 152
	{
		.val_regs = 0x01E0,
153
		.rdata_reg = 0x00d8,
154
		.irq_regs = 0x0178,
155
		.debounce_regs = 0x0190,
156
		.tolerance_regs = 0x018c,
157
		.cmdsrc_regs = 0x0170,
158 159 160
		.names = { "Y", "Z", "AA", "AB" },
	},
	{
161
		.val_regs = 0x01e8,
162
		.rdata_reg = 0x00dc,
163
		.irq_regs = 0x01a8,
164
		.debounce_regs = 0x01c0,
165
		.tolerance_regs = 0x01bc,
166
		.cmdsrc_regs = 0x01a0,
167 168
		.names = { "AC", "", "", "" },
	},
Joel Stanley's avatar
Joel Stanley committed
169 170
};

171 172
enum aspeed_gpio_reg {
	reg_val,
173
	reg_rdata,
174 175 176 177 178 179 180 181 182
	reg_dir,
	reg_irq_enable,
	reg_irq_type0,
	reg_irq_type1,
	reg_irq_type2,
	reg_irq_status,
	reg_debounce_sel1,
	reg_debounce_sel2,
	reg_tolerance,
183 184
	reg_cmdsrc0,
	reg_cmdsrc1,
185
};
Joel Stanley's avatar
Joel Stanley committed
186

187 188
#define GPIO_VAL_VALUE	0x00
#define GPIO_VAL_DIR	0x04
Joel Stanley's avatar
Joel Stanley committed
189 190 191 192 193 194 195

#define GPIO_IRQ_ENABLE	0x00
#define GPIO_IRQ_TYPE0	0x04
#define GPIO_IRQ_TYPE1	0x08
#define GPIO_IRQ_TYPE2	0x0c
#define GPIO_IRQ_STATUS	0x10

196 197 198
#define GPIO_DEBOUNCE_SEL1 0x00
#define GPIO_DEBOUNCE_SEL2 0x04

199 200 201 202 203 204 205
#define GPIO_CMDSRC_0	0x00
#define GPIO_CMDSRC_1	0x04
#define  GPIO_CMDSRC_ARM		0
#define  GPIO_CMDSRC_LPC		1
#define  GPIO_CMDSRC_COLDFIRE		2
#define  GPIO_CMDSRC_RESERVED		3

206 207 208 209 210 211 212 213
/* This will be resolved at compile time */
static inline void __iomem *bank_reg(struct aspeed_gpio *gpio,
				     const struct aspeed_gpio_bank *bank,
				     const enum aspeed_gpio_reg reg)
{
	switch (reg) {
	case reg_val:
		return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
214 215
	case reg_rdata:
		return gpio->base + bank->rdata_reg;
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
	case reg_dir:
		return gpio->base + bank->val_regs + GPIO_VAL_DIR;
	case reg_irq_enable:
		return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
	case reg_irq_type0:
		return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
	case reg_irq_type1:
		return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
	case reg_irq_type2:
		return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
	case reg_irq_status:
		return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
	case reg_debounce_sel1:
		return gpio->base + bank->debounce_regs + GPIO_DEBOUNCE_SEL1;
	case reg_debounce_sel2:
		return gpio->base + bank->debounce_regs + GPIO_DEBOUNCE_SEL2;
	case reg_tolerance:
		return gpio->base + bank->tolerance_regs;
234 235 236 237
	case reg_cmdsrc0:
		return gpio->base + bank->cmdsrc_regs + GPIO_CMDSRC_0;
	case reg_cmdsrc1:
		return gpio->base + bank->cmdsrc_regs + GPIO_CMDSRC_1;
238
	}
239
	BUG();
240 241 242 243 244 245
}

#define GPIO_BANK(x)	((x) >> 5)
#define GPIO_OFFSET(x)	((x) & 0x1f)
#define GPIO_BIT(x)	BIT(GPIO_OFFSET(x))

246 247 248 249
#define _GPIO_SET_DEBOUNCE(t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o))
#define GPIO_SET_DEBOUNCE1(t, o) _GPIO_SET_DEBOUNCE(t, o, 1)
#define GPIO_SET_DEBOUNCE2(t, o) _GPIO_SET_DEBOUNCE(t, o, 0)

Joel Stanley's avatar
Joel Stanley committed
250 251 252 253
static const struct aspeed_gpio_bank *to_bank(unsigned int offset)
{
	unsigned int bank = GPIO_BANK(offset);

254
	WARN_ON(bank >= ARRAY_SIZE(aspeed_gpio_banks));
Joel Stanley's avatar
Joel Stanley committed
255 256 257
	return &aspeed_gpio_banks[bank];
}

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
static inline bool is_bank_props_sentinel(const struct aspeed_bank_props *props)
{
	return !(props->input || props->output);
}

static inline const struct aspeed_bank_props *find_bank_props(
		struct aspeed_gpio *gpio, unsigned int offset)
{
	const struct aspeed_bank_props *props = gpio->config->props;

	while (!is_bank_props_sentinel(props)) {
		if (props->bank == GPIO_BANK(offset))
			return props;
		props++;
	}

	return NULL;
}

static inline bool have_gpio(struct aspeed_gpio *gpio, unsigned int offset)
{
	const struct aspeed_bank_props *props = find_bank_props(gpio, offset);
	const struct aspeed_gpio_bank *bank = to_bank(offset);
	unsigned int group = GPIO_OFFSET(offset) / 8;

	return bank->names[group][0] != '\0' &&
		(!props || ((props->input | props->output) & GPIO_BIT(offset)));
}

static inline bool have_input(struct aspeed_gpio *gpio, unsigned int offset)
{
	const struct aspeed_bank_props *props = find_bank_props(gpio, offset);

	return !props || (props->input & GPIO_BIT(offset));
}

#define have_irq(g, o) have_input((g), (o))
295
#define have_debounce(g, o) have_input((g), (o))
296 297 298 299 300 301 302 303

static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset)
{
	const struct aspeed_bank_props *props = find_bank_props(gpio, offset);

	return !props || (props->output & GPIO_BIT(offset));
}

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio,
					  const struct aspeed_gpio_bank *bank,
					  int bindex, int cmdsrc)
{
	void __iomem *c0 = bank_reg(gpio, bank, reg_cmdsrc0);
	void __iomem *c1 = bank_reg(gpio, bank, reg_cmdsrc1);
	u32 bit, reg;

	/*
	 * Each register controls 4 banks, so take the bottom 2
	 * bits of the bank index, and use them to select the
	 * right control bit (0, 8, 16 or 24).
	 */
	bit = BIT((bindex & 3) << 3);

	/* Source 1 first to avoid illegal 11 combination */
	reg = ioread32(c1);
	if (cmdsrc & 2)
		reg |= bit;
	else
		reg &= ~bit;
	iowrite32(reg, c1);

	/* Then Source 0 */
	reg = ioread32(c0);
	if (cmdsrc & 1)
		reg |= bit;
	else
		reg &= ~bit;
	iowrite32(reg, c0);
}

336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
static bool aspeed_gpio_copro_request(struct aspeed_gpio *gpio,
				      unsigned int offset)
{
	const struct aspeed_gpio_bank *bank = to_bank(offset);

	if (!copro_ops || !gpio->cf_copro_bankmap)
		return false;
	if (!gpio->cf_copro_bankmap[offset >> 3])
		return false;
	if (!copro_ops->request_access)
		return false;

	/* Pause the coprocessor */
	copro_ops->request_access(copro_data);

	/* Change command source back to ARM */
	aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, GPIO_CMDSRC_ARM);

	/* Update cache */
	gpio->dcache[GPIO_BANK(offset)] = ioread32(bank_reg(gpio, bank, reg_rdata));

	return true;
}

static void aspeed_gpio_copro_release(struct aspeed_gpio *gpio,
				      unsigned int offset)
{
	const struct aspeed_gpio_bank *bank = to_bank(offset);

	if (!copro_ops || !gpio->cf_copro_bankmap)
		return;
	if (!gpio->cf_copro_bankmap[offset >> 3])
		return;
	if (!copro_ops->release_access)
		return;

	/* Change command source back to ColdFire */
	aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3,
				      GPIO_CMDSRC_COLDFIRE);

	/* Restart the coprocessor */
	copro_ops->release_access(copro_data);
}

Joel Stanley's avatar
Joel Stanley committed
380 381 382 383 384
static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(gc);
	const struct aspeed_gpio_bank *bank = to_bank(offset);

385
	return !!(ioread32(bank_reg(gpio, bank, reg_val)) & GPIO_BIT(offset));
Joel Stanley's avatar
Joel Stanley committed
386 387 388 389 390 391 392 393 394 395
}

static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,
			      int val)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(gc);
	const struct aspeed_gpio_bank *bank = to_bank(offset);
	void __iomem *addr;
	u32 reg;

396
	addr = bank_reg(gpio, bank, reg_val);
397
	reg = gpio->dcache[GPIO_BANK(offset)];
Joel Stanley's avatar
Joel Stanley committed
398 399 400 401 402

	if (val)
		reg |= GPIO_BIT(offset);
	else
		reg &= ~GPIO_BIT(offset);
403
	gpio->dcache[GPIO_BANK(offset)] = reg;
Joel Stanley's avatar
Joel Stanley committed
404 405 406 407 408 409 410 411 412

	iowrite32(reg, addr);
}

static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,
			    int val)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(gc);
	unsigned long flags;
413
	bool copro;
Joel Stanley's avatar
Joel Stanley committed
414 415

	spin_lock_irqsave(&gpio->lock, flags);
416
	copro = aspeed_gpio_copro_request(gpio, offset);
Joel Stanley's avatar
Joel Stanley committed
417 418 419

	__aspeed_gpio_set(gc, offset, val);

420 421
	if (copro)
		aspeed_gpio_copro_release(gpio, offset);
Joel Stanley's avatar
Joel Stanley committed
422 423 424 425 426 427 428
	spin_unlock_irqrestore(&gpio->lock, flags);
}

static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(gc);
	const struct aspeed_gpio_bank *bank = to_bank(offset);
429
	void __iomem *addr = bank_reg(gpio, bank, reg_dir);
Joel Stanley's avatar
Joel Stanley committed
430
	unsigned long flags;
431
	bool copro;
Joel Stanley's avatar
Joel Stanley committed
432 433
	u32 reg;

434 435 436
	if (!have_input(gpio, offset))
		return -ENOTSUPP;

Joel Stanley's avatar
Joel Stanley committed
437 438
	spin_lock_irqsave(&gpio->lock, flags);

439 440 441 442 443 444 445
	reg = ioread32(addr);
	reg &= ~GPIO_BIT(offset);

	copro = aspeed_gpio_copro_request(gpio, offset);
	iowrite32(reg, addr);
	if (copro)
		aspeed_gpio_copro_release(gpio, offset);
Joel Stanley's avatar
Joel Stanley committed
446 447 448 449 450 451 452 453 454 455 456

	spin_unlock_irqrestore(&gpio->lock, flags);

	return 0;
}

static int aspeed_gpio_dir_out(struct gpio_chip *gc,
			       unsigned int offset, int val)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(gc);
	const struct aspeed_gpio_bank *bank = to_bank(offset);
457
	void __iomem *addr = bank_reg(gpio, bank, reg_dir);
Joel Stanley's avatar
Joel Stanley committed
458
	unsigned long flags;
459
	bool copro;
Joel Stanley's avatar
Joel Stanley committed
460 461
	u32 reg;

462 463 464
	if (!have_output(gpio, offset))
		return -ENOTSUPP;

Joel Stanley's avatar
Joel Stanley committed
465 466
	spin_lock_irqsave(&gpio->lock, flags);

467 468 469 470
	reg = ioread32(addr);
	reg |= GPIO_BIT(offset);

	copro = aspeed_gpio_copro_request(gpio, offset);
471
	__aspeed_gpio_set(gc, offset, val);
472
	iowrite32(reg, addr);
Joel Stanley's avatar
Joel Stanley committed
473

474 475
	if (copro)
		aspeed_gpio_copro_release(gpio, offset);
Joel Stanley's avatar
Joel Stanley committed
476 477 478 479 480 481 482 483 484 485 486 487
	spin_unlock_irqrestore(&gpio->lock, flags);

	return 0;
}

static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(gc);
	const struct aspeed_gpio_bank *bank = to_bank(offset);
	unsigned long flags;
	u32 val;

488
	if (!have_input(gpio, offset))
489
		return 0;
490 491

	if (!have_output(gpio, offset))
492
		return 1;
493

Joel Stanley's avatar
Joel Stanley committed
494 495
	spin_lock_irqsave(&gpio->lock, flags);

496
	val = ioread32(bank_reg(gpio, bank, reg_dir)) & GPIO_BIT(offset);
Joel Stanley's avatar
Joel Stanley committed
497 498 499 500 501 502 503 504

	spin_unlock_irqrestore(&gpio->lock, flags);

	return !val;

}

static inline int irqd_to_aspeed_gpio_data(struct irq_data *d,
505 506 507
					   struct aspeed_gpio **gpio,
					   const struct aspeed_gpio_bank **bank,
					   u32 *bit, int *offset)
Joel Stanley's avatar
Joel Stanley committed
508
{
509
	struct aspeed_gpio *internal;
Joel Stanley's avatar
Joel Stanley committed
510

511
	*offset = irqd_to_hwirq(d);
Joel Stanley's avatar
Joel Stanley committed
512

513 514 515
	internal = irq_data_get_irq_chip_data(d);

	/* This might be a bit of a questionable place to check */
516
	if (!have_irq(internal, *offset))
517 518 519
		return -ENOTSUPP;

	*gpio = internal;
520 521
	*bank = to_bank(*offset);
	*bit = GPIO_BIT(*offset);
Joel Stanley's avatar
Joel Stanley committed
522 523 524 525 526 527 528 529 530 531

	return 0;
}

static void aspeed_gpio_irq_ack(struct irq_data *d)
{
	const struct aspeed_gpio_bank *bank;
	struct aspeed_gpio *gpio;
	unsigned long flags;
	void __iomem *status_addr;
532 533
	int rc, offset;
	bool copro;
Joel Stanley's avatar
Joel Stanley committed
534 535
	u32 bit;

536
	rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset);
Joel Stanley's avatar
Joel Stanley committed
537 538 539
	if (rc)
		return;

540
	status_addr = bank_reg(gpio, bank, reg_irq_status);
Joel Stanley's avatar
Joel Stanley committed
541 542

	spin_lock_irqsave(&gpio->lock, flags);
543 544
	copro = aspeed_gpio_copro_request(gpio, offset);

Joel Stanley's avatar
Joel Stanley committed
545
	iowrite32(bit, status_addr);
546 547 548

	if (copro)
		aspeed_gpio_copro_release(gpio, offset);
Joel Stanley's avatar
Joel Stanley committed
549 550 551 552 553 554 555 556 557 558
	spin_unlock_irqrestore(&gpio->lock, flags);
}

static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)
{
	const struct aspeed_gpio_bank *bank;
	struct aspeed_gpio *gpio;
	unsigned long flags;
	u32 reg, bit;
	void __iomem *addr;
559 560
	int rc, offset;
	bool copro;
Joel Stanley's avatar
Joel Stanley committed
561

562
	rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset);
Joel Stanley's avatar
Joel Stanley committed
563 564 565
	if (rc)
		return;

566
	addr = bank_reg(gpio, bank, reg_irq_enable);
Joel Stanley's avatar
Joel Stanley committed
567 568

	spin_lock_irqsave(&gpio->lock, flags);
569
	copro = aspeed_gpio_copro_request(gpio, offset);
Joel Stanley's avatar
Joel Stanley committed
570 571 572 573 574

	reg = ioread32(addr);
	if (set)
		reg |= bit;
	else
575
		reg &= ~bit;
Joel Stanley's avatar
Joel Stanley committed
576 577
	iowrite32(reg, addr);

578 579
	if (copro)
		aspeed_gpio_copro_release(gpio, offset);
Joel Stanley's avatar
Joel Stanley committed
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
	spin_unlock_irqrestore(&gpio->lock, flags);
}

static void aspeed_gpio_irq_mask(struct irq_data *d)
{
	aspeed_gpio_irq_set_mask(d, false);
}

static void aspeed_gpio_irq_unmask(struct irq_data *d)
{
	aspeed_gpio_irq_set_mask(d, true);
}

static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type)
{
	u32 type0 = 0;
	u32 type1 = 0;
	u32 type2 = 0;
	u32 bit, reg;
	const struct aspeed_gpio_bank *bank;
	irq_flow_handler_t handler;
	struct aspeed_gpio *gpio;
	unsigned long flags;
	void __iomem *addr;
604 605
	int rc, offset;
	bool copro;
Joel Stanley's avatar
Joel Stanley committed
606

607
	rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset);
Joel Stanley's avatar
Joel Stanley committed
608 609 610 611 612 613
	if (rc)
		return -EINVAL;

	switch (type & IRQ_TYPE_SENSE_MASK) {
	case IRQ_TYPE_EDGE_BOTH:
		type2 |= bit;
614
		/* fall through */
Joel Stanley's avatar
Joel Stanley committed
615 616
	case IRQ_TYPE_EDGE_RISING:
		type0 |= bit;
617
		/* fall through */
Joel Stanley's avatar
Joel Stanley committed
618 619 620 621 622
	case IRQ_TYPE_EDGE_FALLING:
		handler = handle_edge_irq;
		break;
	case IRQ_TYPE_LEVEL_HIGH:
		type0 |= bit;
623
		/* fall through */
Joel Stanley's avatar
Joel Stanley committed
624 625 626 627 628 629 630 631 632
	case IRQ_TYPE_LEVEL_LOW:
		type1 |= bit;
		handler = handle_level_irq;
		break;
	default:
		return -EINVAL;
	}

	spin_lock_irqsave(&gpio->lock, flags);
633
	copro = aspeed_gpio_copro_request(gpio, offset);
Joel Stanley's avatar
Joel Stanley committed
634

635
	addr = bank_reg(gpio, bank, reg_irq_type0);
Joel Stanley's avatar
Joel Stanley committed
636 637 638 639
	reg = ioread32(addr);
	reg = (reg & ~bit) | type0;
	iowrite32(reg, addr);

640
	addr = bank_reg(gpio, bank, reg_irq_type1);
Joel Stanley's avatar
Joel Stanley committed
641 642 643 644
	reg = ioread32(addr);
	reg = (reg & ~bit) | type1;
	iowrite32(reg, addr);

645
	addr = bank_reg(gpio, bank, reg_irq_type2);
Joel Stanley's avatar
Joel Stanley committed
646 647 648 649
	reg = ioread32(addr);
	reg = (reg & ~bit) | type2;
	iowrite32(reg, addr);

650 651
	if (copro)
		aspeed_gpio_copro_release(gpio, offset);
Joel Stanley's avatar
Joel Stanley committed
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
	spin_unlock_irqrestore(&gpio->lock, flags);

	irq_set_handler_locked(d, handler);

	return 0;
}

static void aspeed_gpio_irq_handler(struct irq_desc *desc)
{
	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
	struct irq_chip *ic = irq_desc_get_chip(desc);
	struct aspeed_gpio *data = gpiochip_get_data(gc);
	unsigned int i, p, girq;
	unsigned long reg;

	chained_irq_enter(ic, desc);

	for (i = 0; i < ARRAY_SIZE(aspeed_gpio_banks); i++) {
		const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i];

672
		reg = ioread32(bank_reg(data, bank, reg_irq_status));
Joel Stanley's avatar
Joel Stanley committed
673 674

		for_each_set_bit(p, &reg, 32) {
675
			girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
Joel Stanley's avatar
Joel Stanley committed
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
			generic_handle_irq(girq);
		}

	}

	chained_irq_exit(ic, desc);
}

static struct irq_chip aspeed_gpio_irqchip = {
	.name		= "aspeed-gpio",
	.irq_ack	= aspeed_gpio_irq_ack,
	.irq_mask	= aspeed_gpio_irq_mask,
	.irq_unmask	= aspeed_gpio_irq_unmask,
	.irq_set_type	= aspeed_gpio_set_type,
};

692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
static void set_irq_valid_mask(struct aspeed_gpio *gpio)
{
	const struct aspeed_bank_props *props = gpio->config->props;

	while (!is_bank_props_sentinel(props)) {
		unsigned int offset;
		const unsigned long int input = props->input;

		/* Pretty crummy approach, but similar to GPIO core */
		for_each_clear_bit(offset, &input, 32) {
			unsigned int i = props->bank * 32 + offset;

			if (i >= gpio->config->nr_gpios)
				break;

707
			clear_bit(i, gpio->chip.irq.valid_mask);
708 709 710 711 712 713
		}

		props++;
	}
}

Joel Stanley's avatar
Joel Stanley committed
714 715 716 717 718 719 720 721 722 723 724
static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio,
		struct platform_device *pdev)
{
	int rc;

	rc = platform_get_irq(pdev, 0);
	if (rc < 0)
		return rc;

	gpio->irq = rc;

725 726
	set_irq_valid_mask(gpio);

Joel Stanley's avatar
Joel Stanley committed
727 728 729 730 731 732 733 734 735 736 737 738 739
	rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_gpio_irqchip,
			0, handle_bad_irq, IRQ_TYPE_NONE);
	if (rc) {
		dev_info(&pdev->dev, "Could not add irqchip\n");
		return rc;
	}

	gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_gpio_irqchip,
				     gpio->irq, aspeed_gpio_irq_handler);

	return 0;
}

740 741 742 743 744
static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip,
					unsigned int offset, bool enable)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(chip);
	unsigned long flags;
745
	void __iomem *treg;
746
	bool copro;
747 748
	u32 val;

749
	treg = bank_reg(gpio, to_bank(offset), reg_tolerance);
750 751

	spin_lock_irqsave(&gpio->lock, flags);
752 753
	copro = aspeed_gpio_copro_request(gpio, offset);

754
	val = readl(treg);
755 756 757 758 759 760

	if (enable)
		val |= GPIO_BIT(offset);
	else
		val &= ~GPIO_BIT(offset);

761
	writel(val, treg);
762 763 764

	if (copro)
		aspeed_gpio_copro_release(gpio, offset);
765 766 767 768 769
	spin_unlock_irqrestore(&gpio->lock, flags);

	return 0;
}

Joel Stanley's avatar
Joel Stanley committed
770 771
static int aspeed_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
772 773 774
	if (!have_gpio(gpiochip_get_data(chip), offset))
		return -ENODEV;

775
	return pinctrl_gpio_request(chip->base + offset);
Joel Stanley's avatar
Joel Stanley committed
776 777 778 779
}

static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset)
{
780
	pinctrl_gpio_free(chip->base + offset);
Joel Stanley's avatar
Joel Stanley committed
781 782
}

783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
static int usecs_to_cycles(struct aspeed_gpio *gpio, unsigned long usecs,
		u32 *cycles)
{
	u64 rate;
	u64 n;
	u32 r;

	rate = clk_get_rate(gpio->clk);
	if (!rate)
		return -ENOTSUPP;

	n = rate * usecs;
	r = do_div(n, 1000000);

	if (n >= U32_MAX)
		return -ERANGE;

	/* At least as long as the requested time */
	*cycles = n + (!!r);

	return 0;
}

/* Call under gpio->lock */
static int register_allocated_timer(struct aspeed_gpio *gpio,
		unsigned int offset, unsigned int timer)
{
	if (WARN(gpio->offset_timer[offset] != 0,
				"Offset %d already allocated timer %d\n",
				offset, gpio->offset_timer[offset]))
		return -EINVAL;

	if (WARN(gpio->timer_users[timer] == UINT_MAX,
				"Timer user count would overflow\n"))
		return -EPERM;

	gpio->offset_timer[offset] = timer;
	gpio->timer_users[timer]++;

	return 0;
}

/* Call under gpio->lock */
static int unregister_allocated_timer(struct aspeed_gpio *gpio,
		unsigned int offset)
{
	if (WARN(gpio->offset_timer[offset] == 0,
				"No timer allocated to offset %d\n", offset))
		return -EINVAL;

	if (WARN(gpio->timer_users[gpio->offset_timer[offset]] == 0,
				"No users recorded for timer %d\n",
				gpio->offset_timer[offset]))
		return -EINVAL;

	gpio->timer_users[gpio->offset_timer[offset]]--;
	gpio->offset_timer[offset] = 0;

	return 0;
}

/* Call under gpio->lock */
static inline bool timer_allocation_registered(struct aspeed_gpio *gpio,
		unsigned int offset)
{
	return gpio->offset_timer[offset] > 0;
}

/* Call under gpio->lock */
static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset,
		unsigned int timer)
{
	const struct aspeed_gpio_bank *bank = to_bank(offset);
	const u32 mask = GPIO_BIT(offset);
	void __iomem *addr;
	u32 val;

860 861 862
	/* Note: Debounce timer isn't under control of the command
	 * source registers, so no need to sync with the coprocessor
	 */
863
	addr = bank_reg(gpio, bank, reg_debounce_sel1);
864 865 866
	val = ioread32(addr);
	iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE1(timer, offset), addr);

867
	addr = bank_reg(gpio, bank, reg_debounce_sel2);
868 869 870 871 872 873 874 875 876 877 878 879 880
	val = ioread32(addr);
	iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE2(timer, offset), addr);
}

static int enable_debounce(struct gpio_chip *chip, unsigned int offset,
				    unsigned long usecs)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(chip);
	u32 requested_cycles;
	unsigned long flags;
	int rc;
	int i;

881 882 883
	if (!gpio->clk)
		return -EINVAL;

884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 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 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
	rc = usecs_to_cycles(gpio, usecs, &requested_cycles);
	if (rc < 0) {
		dev_warn(chip->parent, "Failed to convert %luus to cycles at %luHz: %d\n",
				usecs, clk_get_rate(gpio->clk), rc);
		return rc;
	}

	spin_lock_irqsave(&gpio->lock, flags);

	if (timer_allocation_registered(gpio, offset)) {
		rc = unregister_allocated_timer(gpio, offset);
		if (rc < 0)
			goto out;
	}

	/* Try to find a timer already configured for the debounce period */
	for (i = 1; i < ARRAY_SIZE(debounce_timers); i++) {
		u32 cycles;

		cycles = ioread32(gpio->base + debounce_timers[i]);
		if (requested_cycles == cycles)
			break;
	}

	if (i == ARRAY_SIZE(debounce_timers)) {
		int j;

		/*
		 * As there are no timers configured for the requested debounce
		 * period, find an unused timer instead
		 */
		for (j = 1; j < ARRAY_SIZE(gpio->timer_users); j++) {
			if (gpio->timer_users[j] == 0)
				break;
		}

		if (j == ARRAY_SIZE(gpio->timer_users)) {
			dev_warn(chip->parent,
					"Debounce timers exhausted, cannot debounce for period %luus\n",
					usecs);

			rc = -EPERM;

			/*
			 * We already adjusted the accounting to remove @offset
			 * as a user of its previous timer, so also configure
			 * the hardware so @offset has timers disabled for
			 * consistency.
			 */
			configure_timer(gpio, offset, 0);
			goto out;
		}

		i = j;

		iowrite32(requested_cycles, gpio->base + debounce_timers[i]);
	}

	if (WARN(i == 0, "Cannot register index of disabled timer\n")) {
		rc = -EINVAL;
		goto out;
	}

	register_allocated_timer(gpio, offset, i);
	configure_timer(gpio, offset, i);

out:
	spin_unlock_irqrestore(&gpio->lock, flags);

	return rc;
}

static int disable_debounce(struct gpio_chip *chip, unsigned int offset)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(chip);
	unsigned long flags;
	int rc;

	spin_lock_irqsave(&gpio->lock, flags);

	rc = unregister_allocated_timer(gpio, offset);
	if (!rc)
		configure_timer(gpio, offset, 0);

	spin_unlock_irqrestore(&gpio->lock, flags);

	return rc;
}

static int set_debounce(struct gpio_chip *chip, unsigned int offset,
				    unsigned long usecs)
{
	struct aspeed_gpio *gpio = gpiochip_get_data(chip);

	if (!have_debounce(gpio, offset))
		return -ENOTSUPP;

	if (usecs)
		return enable_debounce(chip, offset, usecs);

	return disable_debounce(chip, offset);
}

static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
				  unsigned long config)
{
	unsigned long param = pinconf_to_config_param(config);
	u32 arg = pinconf_to_config_argument(config);

	if (param == PIN_CONFIG_INPUT_DEBOUNCE)
		return set_debounce(chip, offset, arg);
	else if (param == PIN_CONFIG_BIAS_DISABLE ||
			param == PIN_CONFIG_BIAS_PULL_DOWN ||
			param == PIN_CONFIG_DRIVE_STRENGTH)
		return pinctrl_gpio_set_config(offset, config);
999 1000 1001 1002
	else if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN ||
			param == PIN_CONFIG_DRIVE_OPEN_SOURCE)
		/* Return -ENOTSUPP to trigger emulation, as per datasheet */
		return -ENOTSUPP;
1003 1004
	else if (param == PIN_CONFIG_PERSIST_STATE)
		return aspeed_gpio_reset_tolerance(chip, offset, arg);
1005 1006 1007 1008

	return -ENOTSUPP;
}

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
/**
 * aspeed_gpio_copro_set_ops - Sets the callbacks used for handhsaking with
 *                             the coprocessor for shared GPIO banks
 * @ops: The callbacks
 * @data: Pointer passed back to the callbacks
 */
int aspeed_gpio_copro_set_ops(const struct aspeed_gpio_copro_ops *ops, void *data)
{
	copro_data = data;
	copro_ops = ops;

	return 0;
}
EXPORT_SYMBOL_GPL(aspeed_gpio_copro_set_ops);

/**
 * aspeed_gpio_copro_grab_gpio - Mark a GPIO used by the coprocessor. The entire
 *                               bank gets marked and any access from the ARM will
 *                               result in handshaking via callbacks.
 * @desc: The GPIO to be marked
 * @vreg_offset: If non-NULL, returns the value register offset in the GPIO space
 * @dreg_offset: If non-NULL, returns the data latch register offset in the GPIO space
 * @bit: If non-NULL, returns the bit number of the GPIO in the registers
 */
int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc,
				u16 *vreg_offset, u16 *dreg_offset, u8 *bit)
{
	struct gpio_chip *chip = gpiod_to_chip(desc);
	struct aspeed_gpio *gpio = gpiochip_get_data(chip);
	int rc = 0, bindex, offset = gpio_chip_hwgpio(desc);
	const struct aspeed_gpio_bank *bank = to_bank(offset);
	unsigned long flags;

	if (!gpio->cf_copro_bankmap)
		gpio->cf_copro_bankmap = kzalloc(gpio->config->nr_gpios >> 3, GFP_KERNEL);
	if (!gpio->cf_copro_bankmap)
		return -ENOMEM;
	if (offset < 0 || offset > gpio->config->nr_gpios)
		return -EINVAL;
	bindex = offset >> 3;

	spin_lock_irqsave(&gpio->lock, flags);

	/* Sanity check, this shouldn't happen */
	if (gpio->cf_copro_bankmap[bindex] == 0xff) {
		rc = -EIO;
		goto bail;
	}
	gpio->cf_copro_bankmap[bindex]++;

	/* Switch command source */
	if (gpio->cf_copro_bankmap[bindex] == 1)
		aspeed_gpio_change_cmd_source(gpio, bank, bindex,
					      GPIO_CMDSRC_COLDFIRE);

	if (vreg_offset)
		*vreg_offset = bank->val_regs;
	if (dreg_offset)
		*dreg_offset = bank->rdata_reg;
	if (bit)
		*bit = GPIO_OFFSET(offset);
 bail:
	spin_unlock_irqrestore(&gpio->lock, flags);
	return rc;
}
EXPORT_SYMBOL_GPL(aspeed_gpio_copro_grab_gpio);

/**
 * aspeed_gpio_copro_release_gpio - Unmark a GPIO used by the coprocessor.
 * @desc: The GPIO to be marked
 */
int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc)
{
	struct gpio_chip *chip = gpiod_to_chip(desc);
	struct aspeed_gpio *gpio = gpiochip_get_data(chip);
	int rc = 0, bindex, offset = gpio_chip_hwgpio(desc);
	const struct aspeed_gpio_bank *bank = to_bank(offset);
	unsigned long flags;

	if (!gpio->cf_copro_bankmap)
		return -ENXIO;

	if (offset < 0 || offset > gpio->config->nr_gpios)
		return -EINVAL;
	bindex = offset >> 3;

	spin_lock_irqsave(&gpio->lock, flags);

	/* Sanity check, this shouldn't happen */
	if (gpio->cf_copro_bankmap[bindex] == 0) {
		rc = -EIO;
		goto bail;
	}
	gpio->cf_copro_bankmap[bindex]--;

	/* Switch command source */
	if (gpio->cf_copro_bankmap[bindex] == 0)
		aspeed_gpio_change_cmd_source(gpio, bank, bindex,
					      GPIO_CMDSRC_ARM);
 bail:
	spin_unlock_irqrestore(&gpio->lock, flags);
	return rc;
}
EXPORT_SYMBOL_GPL(aspeed_gpio_copro_release_gpio);

1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
/*
 * Any banks not specified in a struct aspeed_bank_props array are assumed to
 * have the properties:
 *
 *     { .input = 0xffffffff, .output = 0xffffffff }
 */

static const struct aspeed_bank_props ast2400_bank_props[] = {
	/*     input	  output   */
	{ 5, 0xffffffff, 0x0000ffff }, /* U/V/W/X */
	{ 6, 0x0000000f, 0x0fffff0f }, /* Y/Z/AA/AB, two 4-GPIO holes */
	{ },
};

static const struct aspeed_gpio_config ast2400_config =
	/* 220 for simplicity, really 216 with two 4-GPIO holes, four at end */
	{ .nr_gpios = 220, .props = ast2400_bank_props, };

static const struct aspeed_bank_props ast2500_bank_props[] = {
	/*     input	  output   */
	{ 5, 0xffffffff, 0x0000ffff }, /* U/V/W/X */
	{ 6, 0x0fffffff, 0x0fffffff }, /* Y/Z/AA/AB, 4-GPIO hole */
	{ 7, 0x000000ff, 0x000000ff }, /* AC */
	{ },
};

static const struct aspeed_gpio_config ast2500_config =
	/* 232 for simplicity, actual number is 228 (4-GPIO hole in GPIOAB) */
	{ .nr_gpios = 232, .props = ast2500_bank_props, };

static const struct of_device_id aspeed_gpio_of_table[] = {
	{ .compatible = "aspeed,ast2400-gpio", .data = &ast2400_config, },
	{ .compatible = "aspeed,ast2500-gpio", .data = &ast2500_config, },
	{}
};
MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);

Joel Stanley's avatar
Joel Stanley committed
1151 1152
static int __init aspeed_gpio_probe(struct platform_device *pdev)
{
1153
	const struct of_device_id *gpio_id;
Joel Stanley's avatar
Joel Stanley committed
1154
	struct aspeed_gpio *gpio;
1155
	int rc, i, banks;
Joel Stanley's avatar
Joel Stanley committed
1156 1157 1158 1159 1160

	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
	if (!gpio)
		return -ENOMEM;

1161
	gpio->base = devm_platform_ioremap_resource(pdev, 0);
1162 1163
	if (IS_ERR(gpio->base))
		return PTR_ERR(gpio->base);
Joel Stanley's avatar
Joel Stanley committed
1164 1165 1166

	spin_lock_init(&gpio->lock);

1167 1168 1169 1170
	gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
	if (!gpio_id)
		return -EINVAL;

1171 1172 1173
	gpio->clk = of_clk_get(pdev->dev.of_node, 0);
	if (IS_ERR(gpio->clk)) {
		dev_warn(&pdev->dev,
1174
				"Failed to get clock from devicetree, debouncing disabled\n");
1175 1176 1177
		gpio->clk = NULL;
	}

1178
	gpio->config = gpio_id->data;
Joel Stanley's avatar
Joel Stanley committed
1179

1180
	gpio->chip.parent = &pdev->dev;
1181
	gpio->chip.ngpio = gpio->config->nr_gpios;
Joel Stanley's avatar
Joel Stanley committed
1182 1183 1184 1185 1186 1187 1188
	gpio->chip.direction_input = aspeed_gpio_dir_in;
	gpio->chip.direction_output = aspeed_gpio_dir_out;
	gpio->chip.get_direction = aspeed_gpio_get_direction;
	gpio->chip.request = aspeed_gpio_request;
	gpio->chip.free = aspeed_gpio_free;
	gpio->chip.get = aspeed_gpio_get;
	gpio->chip.set = aspeed_gpio_set;
1189
	gpio->chip.set_config = aspeed_gpio_set_config;
Joel Stanley's avatar
Joel Stanley committed
1190 1191
	gpio->chip.label = dev_name(&pdev->dev);
	gpio->chip.base = -1;
1192
	gpio->chip.irq.need_valid_mask = true;
Joel Stanley's avatar
Joel Stanley committed
1193

1194 1195
	/* Allocate a cache of the output registers */
	banks = gpio->config->nr_gpios >> 5;
1196 1197
	gpio->dcache = devm_kcalloc(&pdev->dev,
				    banks, sizeof(u32), GFP_KERNEL);
1198 1199 1200
	if (!gpio->dcache)
		return -ENOMEM;

1201 1202 1203 1204
	/*
	 * Populate it with initial values read from the HW and switch
	 * all command sources to the ARM by default
	 */
1205
	for (i = 0; i < banks; i++) {
1206 1207
		const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i];
		void __iomem *addr = bank_reg(gpio, bank, reg_rdata);
1208
		gpio->dcache[i] = ioread32(addr);
1209 1210 1211 1212
		aspeed_gpio_change_cmd_source(gpio, bank, 0, GPIO_CMDSRC_ARM);
		aspeed_gpio_change_cmd_source(gpio, bank, 1, GPIO_CMDSRC_ARM);
		aspeed_gpio_change_cmd_source(gpio, bank, 2, GPIO_CMDSRC_ARM);
		aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM);
1213 1214
	}

Joel Stanley's avatar
Joel Stanley committed
1215 1216 1217 1218
	rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
	if (rc < 0)
		return rc;

1219 1220
	gpio->offset_timer =
		devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL);
1221 1222
	if (!gpio->offset_timer)
		return -ENOMEM;
1223

Joel Stanley's avatar
Joel Stanley committed
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
	return aspeed_gpio_setup_irqs(gpio, pdev);
}

static struct platform_driver aspeed_gpio_driver = {
	.driver = {
		.name = KBUILD_MODNAME,
		.of_match_table = aspeed_gpio_of_table,
	},
};

module_platform_driver_probe(aspeed_gpio_driver, aspeed_gpio_probe);

MODULE_DESCRIPTION("Aspeed GPIO Driver");
1237
MODULE_LICENSE("GPL");