1 /*
2  * linux/arch/arm/mach-w90x900/gpio.c
3  *
4  * Generic nuc900 GPIO handling
5  *
6  *  Wan ZongShun <mcuos.com@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 
13 #include <linux/clk.h>
14 #include <linux/errno.h>
15 #include <linux/interrupt.h>
16 #include <linux/irq.h>
17 #include <linux/debugfs.h>
18 #include <linux/seq_file.h>
19 #include <linux/kernel.h>
20 #include <linux/list.h>
21 #include <linux/module.h>
22 #include <linux/io.h>
23 #include <linux/gpio/driver.h>
24 
25 #include <mach/hardware.h>
26 
27 #define GPIO_BASE 		(W90X900_VA_GPIO)
28 #define GPIO_DIR		(0x04)
29 #define GPIO_OUT		(0x08)
30 #define GPIO_IN			(0x0C)
31 #define GROUPINERV		(0x10)
32 #define GPIO_GPIO(Nb)		(0x00000001 << (Nb))
33 
34 #define NUC900_GPIO_CHIP(name, base_gpio, nr_gpio)			\
35 	{								\
36 		.chip = {						\
37 			.label		  = name,			\
38 			.direction_input  = nuc900_dir_input,		\
39 			.direction_output = nuc900_dir_output,		\
40 			.get		  = nuc900_gpio_get,		\
41 			.set		  = nuc900_gpio_set,		\
42 			.base		  = base_gpio,			\
43 			.ngpio		  = nr_gpio,			\
44 		}							\
45 	}
46 
47 struct nuc900_gpio_chip {
48 	struct gpio_chip	chip;
49 	void __iomem		*regbase;	/* Base of group register*/
50 	spinlock_t 		gpio_lock;
51 };
52 
nuc900_gpio_get(struct gpio_chip * chip,unsigned offset)53 static int nuc900_gpio_get(struct gpio_chip *chip, unsigned offset)
54 {
55 	struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
56 	void __iomem *pio = nuc900_gpio->regbase + GPIO_IN;
57 	unsigned int regval;
58 
59 	regval = __raw_readl(pio);
60 	regval &= GPIO_GPIO(offset);
61 
62 	return (regval != 0);
63 }
64 
nuc900_gpio_set(struct gpio_chip * chip,unsigned offset,int val)65 static void nuc900_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
66 {
67 	struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
68 	void __iomem *pio = nuc900_gpio->regbase + GPIO_OUT;
69 	unsigned int regval;
70 	unsigned long flags;
71 
72 	spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags);
73 
74 	regval = __raw_readl(pio);
75 
76 	if (val)
77 		regval |= GPIO_GPIO(offset);
78 	else
79 		regval &= ~GPIO_GPIO(offset);
80 
81 	__raw_writel(regval, pio);
82 
83 	spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags);
84 }
85 
nuc900_dir_input(struct gpio_chip * chip,unsigned offset)86 static int nuc900_dir_input(struct gpio_chip *chip, unsigned offset)
87 {
88 	struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
89 	void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR;
90 	unsigned int regval;
91 	unsigned long flags;
92 
93 	spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags);
94 
95 	regval = __raw_readl(pio);
96 	regval &= ~GPIO_GPIO(offset);
97 	__raw_writel(regval, pio);
98 
99 	spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags);
100 
101 	return 0;
102 }
103 
nuc900_dir_output(struct gpio_chip * chip,unsigned offset,int val)104 static int nuc900_dir_output(struct gpio_chip *chip, unsigned offset, int val)
105 {
106 	struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
107 	void __iomem *outreg = nuc900_gpio->regbase + GPIO_OUT;
108 	void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR;
109 	unsigned int regval;
110 	unsigned long flags;
111 
112 	spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags);
113 
114 	regval = __raw_readl(pio);
115 	regval |= GPIO_GPIO(offset);
116 	__raw_writel(regval, pio);
117 
118 	regval = __raw_readl(outreg);
119 
120 	if (val)
121 		regval |= GPIO_GPIO(offset);
122 	else
123 		regval &= ~GPIO_GPIO(offset);
124 
125 	__raw_writel(regval, outreg);
126 
127 	spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags);
128 
129 	return 0;
130 }
131 
132 static struct nuc900_gpio_chip nuc900_gpio[] = {
133 	NUC900_GPIO_CHIP("GROUPC", 0, 16),
134 	NUC900_GPIO_CHIP("GROUPD", 16, 10),
135 	NUC900_GPIO_CHIP("GROUPE", 26, 14),
136 	NUC900_GPIO_CHIP("GROUPF", 40, 10),
137 	NUC900_GPIO_CHIP("GROUPG", 50, 17),
138 	NUC900_GPIO_CHIP("GROUPH", 67, 8),
139 	NUC900_GPIO_CHIP("GROUPI", 75, 17),
140 };
141 
nuc900_init_gpio(int nr_group)142 void __init nuc900_init_gpio(int nr_group)
143 {
144 	unsigned	i;
145 	struct nuc900_gpio_chip *gpio_chip;
146 
147 	for (i = 0; i < nr_group; i++) {
148 		gpio_chip = &nuc900_gpio[i];
149 		spin_lock_init(&gpio_chip->gpio_lock);
150 		gpio_chip->regbase = GPIO_BASE + i * GROUPINERV;
151 		gpiochip_add_data(&gpio_chip->chip, gpio_chip);
152 	}
153 }
154