You need to sign in or sign up before continuing.
gpio.c 6.8 KB
Newer Older
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
/*
 *  Miscellaneous functions for IDT EB434 board
 *
 *  Copyright 2004 IDT Inc. (rischelp@idt.com)
 *  Copyright 2006 Phil Sutter <n0-1@freewrt.org>
 *  Copyright 2007 Florian Fainelli <florian@openwrt.org>
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *  You should have received a copy of the  GNU General Public License along
 *  with this program; if not, write  to the Free Software Foundation, Inc.,
 *  675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
34
#include <linux/gpio.h>
35 36

#include <asm/mach-rc32434/rb.h>
37 38 39 40 41 42
#include <asm/mach-rc32434/gpio.h>

struct rb532_gpio_chip {
	struct gpio_chip chip;
	void __iomem	 *regbase;
};
43 44 45 46 47 48

struct mpmc_device dev3;

static struct resource rb532_gpio_reg0_res[] = {
	{
		.name 	= "gpio_reg0",
49 50
		.start 	= REGBASE + GPIOBASE,
		.end 	= REGBASE + GPIOBASE + sizeof(struct rb532_gpio_reg) - 1,
51 52 53 54 55 56 57
		.flags 	= IORESOURCE_MEM,
	}
};

static struct resource rb532_dev3_ctl_res[] = {
	{
		.name	= "dev3_ctl",
58 59
		.start	= REGBASE + DEV3BASE,
		.end	= REGBASE + DEV3BASE + sizeof(struct dev_reg) - 1,
60 61 62 63 64 65
		.flags	= IORESOURCE_MEM,
	}
};

void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val)
{
66 67
	unsigned long flags;
	unsigned data;
68 69 70 71
	unsigned i = 0;

	spin_lock_irqsave(&dev3.lock, flags);

72
	data = readl(IDT434_REG_BASE + reg_offs);
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
	for (i = 0; i != len; ++i) {
		if (val & (1 << i))
			data |= (1 << (i + bit));
		else
			data &= ~(1 << (i + bit));
	}
	writel(data, (IDT434_REG_BASE + reg_offs));

	spin_unlock_irqrestore(&dev3.lock, flags);
}
EXPORT_SYMBOL(set_434_reg);

unsigned get_434_reg(unsigned reg_offs)
{
	return readl(IDT434_REG_BASE + reg_offs);
}
EXPORT_SYMBOL(get_434_reg);

void set_latch_u5(unsigned char or_mask, unsigned char nand_mask)
{
93
	unsigned long flags;
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109

	spin_lock_irqsave(&dev3.lock, flags);

	dev3.state = (dev3.state | or_mask) & ~nand_mask;
	writel(dev3.state, &dev3.base);

	spin_unlock_irqrestore(&dev3.lock, flags);
}
EXPORT_SYMBOL(set_latch_u5);

unsigned char get_latch_u5(void)
{
	return dev3.state;
}
EXPORT_SYMBOL(get_latch_u5);

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
/* rb532_set_bit - sanely set a bit
 *
 * bitval: new value for the bit
 * offset: bit index in the 4 byte address range
 * ioaddr: 4 byte aligned address being altered
 */
static inline void rb532_set_bit(unsigned bitval,
		unsigned offset, void __iomem *ioaddr)
{
	unsigned long flags;
	u32 val;

	bitval = !!bitval;              /* map parameter to {0,1} */

	local_irq_save(flags);

	val = readl(ioaddr);
	val &= ~( ~bitval << offset );   /* unset bit if bitval == 0 */
	val |=  (  bitval << offset );   /* set bit if bitval == 1 */
	writel(val, ioaddr);

	local_irq_restore(flags);
}

/* rb532_get_bit - read a bit
 *
 * returns the boolean state of the bit, which may be > 1
 */
static inline int rb532_get_bit(unsigned offset, void __iomem *ioaddr)
{
	return (readl(ioaddr) & (1 << offset));
}

143 144 145
/*
 * Return GPIO level */
static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset)
146
{
147 148 149
	struct rb532_gpio_chip	*gpch;

	gpch = container_of(chip, struct rb532_gpio_chip, chip);
150
	return rb532_get_bit(offset, gpch->regbase + GPIOD);
151 152
}

153 154 155 156 157
/*
 * Set output GPIO level
 */
static void rb532_gpio_set(struct gpio_chip *chip,
				unsigned offset, int value)
158
{
159
	struct rb532_gpio_chip	*gpch;
160

161
	gpch = container_of(chip, struct rb532_gpio_chip, chip);
162
	rb532_set_bit(value, offset, gpch->regbase + GPIOD);
163 164
}

165 166 167 168
/*
 * Set GPIO direction to input
 */
static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
169
{
170
	struct rb532_gpio_chip	*gpch;
171

172
	gpch = container_of(chip, struct rb532_gpio_chip, chip);
173

174 175
	if (rb532_get_bit(offset, gpch->regbase + GPIOFUNC))
		return 1;	/* alternate function, GPIOCFG is ignored */
176

177
	rb532_set_bit(0, offset, gpch->regbase + GPIOCFG);
178 179 180
	return 0;
}

181 182 183 184 185
/*
 * Set GPIO direction to output
 */
static int rb532_gpio_direction_output(struct gpio_chip *chip,
					unsigned offset, int value)
186
{
187 188 189 190
	struct rb532_gpio_chip	*gpch;

	gpch = container_of(chip, struct rb532_gpio_chip, chip);

191 192
	if (rb532_get_bit(offset, gpch->regbase + GPIOFUNC))
		return 1;	/* alternate function, GPIOCFG is ignored */
193

194 195 196 197
	/* set the initial output value */
	rb532_set_bit(value, offset, gpch->regbase + GPIOD);

	rb532_set_bit(1, offset, gpch->regbase + GPIOCFG);
198
	return 0;
199 200
}

201 202 203 204 205 206 207 208 209 210 211 212 213
static struct rb532_gpio_chip rb532_gpio_chip[] = {
	[0] = {
		.chip = {
			.label			= "gpio0",
			.direction_input	= rb532_gpio_direction_input,
			.direction_output	= rb532_gpio_direction_output,
			.get			= rb532_gpio_get,
			.set			= rb532_gpio_set,
			.base			= 0,
			.ngpio			= 32,
		},
	},
};
214

215
/*
216
 * Set GPIO interrupt level
217
 */
218
void rb532_gpio_set_ilevel(int bit, unsigned gpio)
219
{
220
	rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOILEVEL);
221
}
222
EXPORT_SYMBOL(rb532_gpio_set_ilevel);
223

224
/*
225
 * Set GPIO interrupt status
226
 */
227
void rb532_gpio_set_istat(int bit, unsigned gpio)
228
{
229
	rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOISTAT);
230
}
231
EXPORT_SYMBOL(rb532_gpio_set_istat);
232

233
/*
234
 * Configure GPIO alternate function
235
 */
236
static void rb532_gpio_set_func(int bit, unsigned gpio)
237
{
238
       rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOFUNC);
239
}
240

241 242
int __init rb532_gpio_init(void)
{
243
	struct resource *r;
244

245 246 247 248
	r = rb532_gpio_reg0_res;
	rb532_gpio_chip->regbase = ioremap_nocache(r->start, r->end - r->start);

	if (!rb532_gpio_chip->regbase) {
249 250 251 252
		printk(KERN_ERR "rb532: cannot remap GPIO register 0\n");
		return -ENXIO;
	}

253 254 255 256 257
	/* Register our GPIO chip */
	gpiochip_add(&rb532_gpio_chip->chip);

	r = rb532_dev3_ctl_res;
	dev3.base = ioremap_nocache(r->start, r->end - r->start);
258 259 260 261 262 263

	if (!dev3.base) {
		printk(KERN_ERR "rb532: cannot remap device controller 3\n");
		return -ENXIO;
	}

264 265 266 267 268
	/* configure CF_GPIO_NUM as CFRDY IRQ source */
	rb532_gpio_set_func(0, CF_GPIO_NUM);
	rb532_gpio_direction_input(&rb532_gpio_chip->chip, CF_GPIO_NUM);
	rb532_gpio_set_ilevel(1, CF_GPIO_NUM);
	rb532_gpio_set_istat(0, CF_GPIO_NUM);
269

270 271 272
	return 0;
}
arch_initcall(rb532_gpio_init);