summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-w90x900/gpio.c
blob: cb5df211f1ed6abf160a3b92aacfda45b24b41e2 (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
// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/arch/arm/mach-w90x900/gpio.c
 *
 * Generic nuc900 GPIO handling
 *
 *  Wan ZongShun <mcuos.com@gmail.com>
 */

#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/driver.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 NUC900_GPIO_CHIP(name, base_gpio, nr_gpio)			\
	{								\
		.chip = {						\
			.label		  = name,			\
			.direction_input  = nuc900_dir_input,		\
			.direction_output = nuc900_dir_output,		\
			.get		  = nuc900_gpio_get,		\
			.set		  = nuc900_gpio_set,		\
			.base		  = base_gpio,			\
			.ngpio		  = nr_gpio,			\
		}							\
	}

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

static int nuc900_gpio_get(struct gpio_chip *chip, unsigned offset)
{
	struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
	void __iomem *pio = nuc900_gpio->regbase + GPIO_IN;
	unsigned int regval;

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

	return (regval != 0);
}

static void nuc900_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
	struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
	void __iomem *pio = nuc900_gpio->regbase + GPIO_OUT;
	unsigned int regval;
	unsigned long flags;

	spin_lock_irqsave(&nuc900_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(&nuc900_gpio->gpio_lock, flags);
}

static int nuc900_dir_input(struct gpio_chip *chip, unsigned offset)
{
	struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
	void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR;
	unsigned int regval;
	unsigned long flags;

	spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags);

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

	spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags);

	return 0;
}

static int nuc900_dir_output(struct gpio_chip *chip, unsigned offset, int val)
{
	struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
	void __iomem *outreg = nuc900_gpio->regbase + GPIO_OUT;
	void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR;
	unsigned int regval;
	unsigned long flags;

	spin_lock_irqsave(&nuc900_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(&nuc900_gpio->gpio_lock, flags);

	return 0;
}

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

void __init nuc900_init_gpio(int nr_group)
{
	unsigned	i;
	struct nuc900_gpio_chip *gpio_chip;

	for (i = 0; i < nr_group; i++) {
		gpio_chip = &nuc900_gpio[i];
		spin_lock_init(&gpio_chip->gpio_lock);
		gpio_chip->regbase = GPIO_BASE + i * GROUPINERV;
		gpiochip_add_data(&gpio_chip->chip, gpio_chip);
	}
}