summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-w90x900/gpio.c
blob: c72e0dfa182565d3b93611eb9d2b254c2c2d56d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * linux/arch/arm/mach-w90p910/gpio.c
 *
 * Generic w90p910 GPIO handling
 *
 *  Wan ZongShun <mcuos.com@gmail.com>
 *
 * 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.
 */

#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/gpio.h>

#include <mach/hardware.h>

#define GPIO_BASE 		(W90X900_VA_GPIO)
#define GPIO_DIR		(0x04)
#define GPIO_OUT		(0x08)
#define GPIO_IN			(0x0C)
#define GROUPINERV		(0x10)
#define GPIO_GPIO(Nb)		(0x00000001 << (Nb))
#define to_w90p910_gpio_chip(c) container_of(c, struct w90p910_gpio_chip, chip)

#define W90P910_GPIO_CHIP(name, base_gpio, nr_gpio)			\
	{								\
		.chip = {						\
			.label		  = name,			\
			.direction_input  = w90p910_dir_input,		\
			.direction_output = w90p910_dir_output,		\
			.get		  = w90p910_gpio_get,		\
			.set		  = w90p910_gpio_set,		\
			.base		  = base_gpio,			\
			.ngpio		  = nr_gpio,			\
		}							\
	}

struct w90p910_gpio_chip {
	struct gpio_chip	chip;
	void __iomem		*regbase;	/* Base of group register*/
	spinlock_t 		gpio_lock;
};

static int w90p910_gpio_get(struct gpio_chip *chip, unsigned offset)
{
	struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
	void __iomem *pio = w90p910_gpio->regbase + GPIO_IN;
	unsigned int regval;

	regval = __raw_readl(pio);
	regval &= GPIO_GPIO(offset);

	return (regval != 0);
}

static void w90p910_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
	struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
	void __iomem *pio = w90p910_gpio->regbase + GPIO_OUT;
	unsigned int regval;
	unsigned long flags;

	spin_lock_irqsave(&w90p910_gpio->gpio_lock, flags);

	regval = __raw_readl(pio);

	if (val)
		regval |= GPIO_GPIO(offset);
	else
		regval &= ~GPIO_GPIO(offset);

	__raw_writel(regval, pio);

	spin_unlock_irqrestore(&w90p910_gpio->gpio_lock, flags);
}

static int w90p910_dir_input(struct gpio_chip *chip, unsigned offset)
{
	struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
	void __iomem *pio = w90p910_gpio->regbase + GPIO_DIR;
	unsigned int regval;
	unsigned long flags;

	spin_lock_irqsave(&w90p910_gpio->gpio_lock, flags);

	regval = __raw_readl(pio);
	regval &= ~GPIO_GPIO(offset);
	__raw_writel(regval, pio);

	spin_unlock_irqrestore(&w90p910_gpio->gpio_lock, flags);

	return 0;
}

static int w90p910_dir_output(struct gpio_chip *chip, unsigned offset, int val)
{
	struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
	void __iomem *outreg = w90p910_gpio->regbase + GPIO_OUT;
	void __iomem *pio = w90p910_gpio->regbase + GPIO_DIR;
	unsigned int regval;
	unsigned long flags;

	spin_lock_irqsave(&w90p910_gpio->gpio_lock, flags);

	regval = __raw_readl(pio);
	regval |= GPIO_GPIO(offset);
	__raw_writel(regval, pio);

	regval = __raw_readl(outreg);

	if (val)
		regval |= GPIO_GPIO(offset);
	else
		regval &= ~GPIO_GPIO(offset);

	__raw_writel(regval, outreg);

	spin_unlock_irqrestore(&w90p910_gpio->gpio_lock, flags);

	return 0;
}

static struct w90p910_gpio_chip w90p910_gpio[] = {
	W90P910_GPIO_CHIP("GROUPC", 0, 16),
	W90P910_GPIO_CHIP("GROUPD", 16, 10),
	W90P910_GPIO_CHIP("GROUPE", 26, 14),
	W90P910_GPIO_CHIP("GROUPF", 40, 10),
	W90P910_GPIO_CHIP("GROUPG", 50, 17),
	W90P910_GPIO_CHIP("GROUPH", 67, 8),
	W90P910_GPIO_CHIP("GROUPI", 75, 17),
};

void __init w90p910_init_gpio(int nr_group)
{
	unsigned	i;
	struct w90p910_gpio_chip *gpio_chip;

	for (i = 0; i < nr_group; i++) {
		gpio_chip = &w90p910_gpio[i];
		spin_lock_init(&gpio_chip->gpio_lock);
		gpio_chip->regbase = GPIO_BASE + i * GROUPINERV;
		gpiochip_add(&gpio_chip->chip);
	}
}
OpenPOWER on IntegriCloud