blob: 3419b67f422141eee0eb7bac98493d312b476a6e [file] [log] [blame]
Kukjin Kim1f323cf2010-01-19 15:30:54 +09001/* arch/arm/plat-samsung/gpiolib.c
2 *
3 * Copyright 2008 Openmoko, Inc.
4 * Copyright 2008 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 * http://armlinux.simtec.co.uk/
7 *
8 * Copyright (c) 2009 Samsung Electronics Co., Ltd.
9 * http://www.samsung.com/
10 *
11 * SAMSUNG - GPIOlib support
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17
18#include <linux/kernel.h>
19#include <linux/irq.h>
20#include <linux/io.h>
21#include <mach/gpio.h>
22#include <plat/gpio-core.h>
23#include <plat/gpio-cfg.h>
24#include <plat/gpio-cfg-helpers.h>
25
26#ifndef DEBUG_GPIO
27#define gpio_dbg(x...) do { } while (0)
28#else
29#define gpio_dbg(x...) printk(KERN_DEBUG x)
30#endif
31
32/* The samsung_gpiolib_4bit routines are to control the gpio banks where
33 * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
34 * following example:
35 *
36 * base + 0x00: Control register, 4 bits per gpio
37 * gpio n: 4 bits starting at (4*n)
38 * 0000 = input, 0001 = output, others mean special-function
39 * base + 0x04: Data register, 1 bit per gpio
40 * bit n: data bit n
41 *
42 * Note, since the data register is one bit per gpio and is at base + 0x4
43 * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
44 * the output.
45*/
46
47int samsung_gpiolib_4bit_input(struct gpio_chip *chip, unsigned int offset)
48{
49 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
50 void __iomem *base = ourchip->base;
51 unsigned long con;
52
53 con = __raw_readl(base + GPIOCON_OFF);
54 con &= ~(0xf << con_4bit_shift(offset));
55 __raw_writel(con, base + GPIOCON_OFF);
56
57 gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
58
59 return 0;
60}
61
62int samsung_gpiolib_4bit_output(struct gpio_chip *chip,
63 unsigned int offset, int value)
64{
65 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
66 void __iomem *base = ourchip->base;
67 unsigned long con;
68 unsigned long dat;
69
70 con = __raw_readl(base + GPIOCON_OFF);
71 con &= ~(0xf << con_4bit_shift(offset));
72 con |= 0x1 << con_4bit_shift(offset);
73
74 dat = __raw_readl(base + GPIODAT_OFF);
75
76 if (value)
77 dat |= 1 << offset;
78 else
79 dat &= ~(1 << offset);
80
81 __raw_writel(dat, base + GPIODAT_OFF);
82 __raw_writel(con, base + GPIOCON_OFF);
83 __raw_writel(dat, base + GPIODAT_OFF);
84
85 gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
86
87 return 0;
88}
89
90/* The next set of routines are for the case where the GPIO configuration
91 * registers are 4 bits per GPIO but there is more than one register (the
92 * bank has more than 8 GPIOs.
93 *
94 * This case is the similar to the 4 bit case, but the registers are as
95 * follows:
96 *
97 * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
98 * gpio n: 4 bits starting at (4*n)
99 * 0000 = input, 0001 = output, others mean special-function
100 * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
101 * gpio n: 4 bits starting at (4*n)
102 * 0000 = input, 0001 = output, others mean special-function
103 * base + 0x08: Data register, 1 bit per gpio
104 * bit n: data bit n
105 *
106 * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
107 * store the 'base + 0x4' address so that these routines see the data
108 * register at ourchip->base + 0x04.
109*/
110
111int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, unsigned int offset)
112{
113 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
114 void __iomem *base = ourchip->base;
115 void __iomem *regcon = base;
116 unsigned long con;
117
118 if (offset > 7)
119 offset -= 8;
120 else
121 regcon -= 4;
122
123 con = __raw_readl(regcon);
124 con &= ~(0xf << con_4bit_shift(offset));
125 __raw_writel(con, regcon);
126
127 gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con);
128
129 return 0;
130}
131
132int samsung_gpiolib_4bit2_output(struct gpio_chip *chip,
133 unsigned int offset, int value)
134{
135 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
136 void __iomem *base = ourchip->base;
137 void __iomem *regcon = base;
138 unsigned long con;
139 unsigned long dat;
140 unsigned con_offset = offset;
141
142 if (con_offset > 7)
143 con_offset -= 8;
144 else
145 regcon -= 4;
146
147 con = __raw_readl(regcon);
148 con &= ~(0xf << con_4bit_shift(con_offset));
149 con |= 0x1 << con_4bit_shift(con_offset);
150
151 dat = __raw_readl(base + GPIODAT_OFF);
152
153 if (value)
154 dat |= 1 << offset;
155 else
156 dat &= ~(1 << offset);
157
158 __raw_writel(dat, base + GPIODAT_OFF);
159 __raw_writel(con, regcon);
160 __raw_writel(dat, base + GPIODAT_OFF);
161
162 gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
163
164 return 0;
165}
166
167void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
168{
169 chip->chip.direction_input = samsung_gpiolib_4bit_input;
170 chip->chip.direction_output = samsung_gpiolib_4bit_output;
171 chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
172}
173
174void __init samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
175{
176 chip->chip.direction_input = samsung_gpiolib_4bit2_input;
177 chip->chip.direction_output = samsung_gpiolib_4bit2_output;
178 chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
179}
180
181void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,
182 int nr_chips)
183{
184 for (; nr_chips > 0; nr_chips--, chip++) {
185 samsung_gpiolib_add_4bit(chip);
186 s3c_gpiolib_add(chip);
187 }
188}
189
190void __init samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip,
191 int nr_chips)
192{
193 for (; nr_chips > 0; nr_chips--, chip++) {
194 samsung_gpiolib_add_4bit2(chip);
195 s3c_gpiolib_add(chip);
196 }
197}