gpio.c 3.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 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);
	}
}