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.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#define to_nuc900_gpio_chip(c) container_of(c, struct nuc900_gpio_chip, chip) 34 35#define NUC900_GPIO_CHIP(name, base_gpio, nr_gpio) \ 36 { \ 37 .chip = { \ 38 .label = name, \ 39 .direction_input = nuc900_dir_input, \ 40 .direction_output = nuc900_dir_output, \ 41 .get = nuc900_gpio_get, \ 42 .set = nuc900_gpio_set, \ 43 .base = base_gpio, \ 44 .ngpio = nr_gpio, \ 45 } \ 46 } 47 48struct nuc900_gpio_chip { 49 struct gpio_chip chip; 50 void __iomem *regbase; /* Base of group register*/ 51 spinlock_t gpio_lock; 52}; 53 54static int nuc900_gpio_get(struct gpio_chip *chip, unsigned offset) 55{ 56 struct nuc900_gpio_chip *nuc900_gpio = to_nuc900_gpio_chip(chip); 57 void __iomem *pio = nuc900_gpio->regbase + GPIO_IN; 58 unsigned int regval; 59 60 regval = __raw_readl(pio); 61 regval &= GPIO_GPIO(offset); 62 63 return (regval != 0); 64} 65 66static void nuc900_gpio_set(struct gpio_chip *chip, unsigned offset, int val) 67{ 68 struct nuc900_gpio_chip *nuc900_gpio = to_nuc900_gpio_chip(chip); 69 void __iomem *pio = nuc900_gpio->regbase + GPIO_OUT; 70 unsigned int regval; 71 unsigned long flags; 72 73 spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags); 74 75 regval = __raw_readl(pio); 76 77 if (val) 78 regval |= GPIO_GPIO(offset); 79 else 80 regval &= ~GPIO_GPIO(offset); 81 82 __raw_writel(regval, pio); 83 84 spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags); 85} 86 87static int nuc900_dir_input(struct gpio_chip *chip, unsigned offset) 88{ 89 struct nuc900_gpio_chip *nuc900_gpio = to_nuc900_gpio_chip(chip); 90 void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR; 91 unsigned int regval; 92 unsigned long flags; 93 94 spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags); 95 96 regval = __raw_readl(pio); 97 regval &= ~GPIO_GPIO(offset); 98 __raw_writel(regval, pio); 99 100 spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags); 101 102 return 0; 103} 104 105static int nuc900_dir_output(struct gpio_chip *chip, unsigned offset, int val) 106{ 107 struct nuc900_gpio_chip *nuc900_gpio = to_nuc900_gpio_chip(chip); 108 void __iomem *outreg = nuc900_gpio->regbase + GPIO_OUT; 109 void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR; 110 unsigned int regval; 111 unsigned long flags; 112 113 spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags); 114 115 regval = __raw_readl(pio); 116 regval |= GPIO_GPIO(offset); 117 __raw_writel(regval, pio); 118 119 regval = __raw_readl(outreg); 120 121 if (val) 122 regval |= GPIO_GPIO(offset); 123 else 124 regval &= ~GPIO_GPIO(offset); 125 126 __raw_writel(regval, outreg); 127 128 spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags); 129 130 return 0; 131} 132 133static struct nuc900_gpio_chip nuc900_gpio[] = { 134 NUC900_GPIO_CHIP("GROUPC", 0, 16), 135 NUC900_GPIO_CHIP("GROUPD", 16, 10), 136 NUC900_GPIO_CHIP("GROUPE", 26, 14), 137 NUC900_GPIO_CHIP("GROUPF", 40, 10), 138 NUC900_GPIO_CHIP("GROUPG", 50, 17), 139 NUC900_GPIO_CHIP("GROUPH", 67, 8), 140 NUC900_GPIO_CHIP("GROUPI", 75, 17), 141}; 142 143void __init nuc900_init_gpio(int nr_group) 144{ 145 unsigned i; 146 struct nuc900_gpio_chip *gpio_chip; 147 148 for (i = 0; i < nr_group; i++) { 149 gpio_chip = &nuc900_gpio[i]; 150 spin_lock_init(&gpio_chip->gpio_lock); 151 gpio_chip->regbase = GPIO_BASE + i * GROUPINERV; 152 gpiochip_add(&gpio_chip->chip); 153 } 154} 155