]>
Commit | Line | Data |
---|---|---|
9fa32c6b | 1 | /* |
9fa32c6b PG |
2 | * Generic PMC MSP71xx GPIO handling. These base gpio are controlled by two |
3 | * types of registers. The data register sets the output level when in output | |
4 | * mode and when in input mode will contain the value at the input. The config | |
5 | * register sets the various modes for each gpio. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * @author Patrick Glass <patrickglass@gmail.com> | |
12 | */ | |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/gpio.h> | |
18 | #include <linux/spinlock.h> | |
19 | #include <linux/io.h> | |
20 | ||
21 | #define MSP71XX_CFG_OFFSET(gpio) (4 * (gpio)) | |
22 | #define CONF_MASK 0x0F | |
23 | #define MSP71XX_GPIO_INPUT 0x01 | |
24 | #define MSP71XX_GPIO_OUTPUT 0x08 | |
25 | ||
26 | #define MSP71XX_GPIO_BASE 0x0B8400000L | |
27 | ||
28 | #define to_msp71xx_gpio_chip(c) container_of(c, struct msp71xx_gpio_chip, chip) | |
29 | ||
30 | static spinlock_t gpio_lock; | |
31 | ||
32 | /* | |
33 | * struct msp71xx_gpio_chip - container for gpio chip and registers | |
34 | * @chip: chip structure for the specified gpio bank | |
35 | * @data_reg: register for reading and writing the gpio pin value | |
36 | * @config_reg: register to set the mode for the gpio pin bank | |
37 | * @out_drive_reg: register to set the output drive mode for the gpio pin bank | |
38 | */ | |
39 | struct msp71xx_gpio_chip { | |
40 | struct gpio_chip chip; | |
41 | void __iomem *data_reg; | |
42 | void __iomem *config_reg; | |
43 | void __iomem *out_drive_reg; | |
44 | }; | |
45 | ||
46 | /* | |
47 | * msp71xx_gpio_get() - return the chip's gpio value | |
48 | * @chip: chip structure which controls the specified gpio | |
49 | * @offset: gpio whose value will be returned | |
50 | * | |
51 | * It will return 0 if gpio value is low and other if high. | |
52 | */ | |
53 | static int msp71xx_gpio_get(struct gpio_chip *chip, unsigned offset) | |
54 | { | |
55 | struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip); | |
56 | ||
57 | return __raw_readl(msp_chip->data_reg) & (1 << offset); | |
58 | } | |
59 | ||
60 | /* | |
61 | * msp71xx_gpio_set() - set the output value for the gpio | |
62 | * @chip: chip structure who controls the specified gpio | |
63 | * @offset: gpio whose value will be assigned | |
64 | * @value: logic level to assign to the gpio initially | |
65 | * | |
66 | * This will set the gpio bit specified to the desired value. It will set the | |
67 | * gpio pin low if value is 0 otherwise it will be high. | |
68 | */ | |
69 | static void msp71xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |
70 | { | |
71 | struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip); | |
72 | unsigned long flags; | |
73 | u32 data; | |
74 | ||
75 | spin_lock_irqsave(&gpio_lock, flags); | |
76 | ||
77 | data = __raw_readl(msp_chip->data_reg); | |
78 | if (value) | |
79 | data |= (1 << offset); | |
80 | else | |
81 | data &= ~(1 << offset); | |
82 | __raw_writel(data, msp_chip->data_reg); | |
83 | ||
84 | spin_unlock_irqrestore(&gpio_lock, flags); | |
85 | } | |
86 | ||
87 | /* | |
88 | * msp71xx_set_gpio_mode() - declare the mode for a gpio | |
89 | * @chip: chip structure which controls the specified gpio | |
90 | * @offset: gpio whose value will be assigned | |
91 | * @mode: desired configuration for the gpio (see datasheet) | |
92 | * | |
93 | * It will set the gpio pin config to the @mode value passed in. | |
94 | */ | |
95 | static int msp71xx_set_gpio_mode(struct gpio_chip *chip, | |
96 | unsigned offset, int mode) | |
97 | { | |
98 | struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip); | |
99 | const unsigned bit_offset = MSP71XX_CFG_OFFSET(offset); | |
100 | unsigned long flags; | |
101 | u32 cfg; | |
102 | ||
103 | spin_lock_irqsave(&gpio_lock, flags); | |
104 | ||
105 | cfg = __raw_readl(msp_chip->config_reg); | |
106 | cfg &= ~(CONF_MASK << bit_offset); | |
107 | cfg |= (mode << bit_offset); | |
108 | __raw_writel(cfg, msp_chip->config_reg); | |
109 | ||
110 | spin_unlock_irqrestore(&gpio_lock, flags); | |
111 | ||
112 | return 0; | |
113 | } | |
114 | ||
115 | /* | |
116 | * msp71xx_direction_output() - declare the direction mode for a gpio | |
117 | * @chip: chip structure which controls the specified gpio | |
118 | * @offset: gpio whose value will be assigned | |
119 | * @value: logic level to assign to the gpio initially | |
120 | * | |
121 | * This call will set the mode for the @gpio to output. It will set the | |
122 | * gpio pin low if value is 0 otherwise it will be high. | |
123 | */ | |
124 | static int msp71xx_direction_output(struct gpio_chip *chip, | |
125 | unsigned offset, int value) | |
126 | { | |
127 | msp71xx_gpio_set(chip, offset, value); | |
128 | ||
129 | return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_OUTPUT); | |
130 | } | |
131 | ||
132 | /* | |
133 | * msp71xx_direction_input() - declare the direction mode for a gpio | |
134 | * @chip: chip structure which controls the specified gpio | |
135 | * @offset: gpio whose to which the value will be assigned | |
136 | * | |
137 | * This call will set the mode for the @gpio to input. | |
138 | */ | |
139 | static int msp71xx_direction_input(struct gpio_chip *chip, unsigned offset) | |
140 | { | |
141 | return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_INPUT); | |
142 | } | |
143 | ||
144 | /* | |
145 | * msp71xx_set_output_drive() - declare the output drive for the gpio line | |
146 | * @gpio: gpio pin whose output drive you wish to modify | |
147 | * @value: zero for active drain 1 for open drain drive | |
148 | * | |
149 | * This call will set the output drive mode for the @gpio to output. | |
150 | */ | |
151 | int msp71xx_set_output_drive(unsigned gpio, int value) | |
152 | { | |
153 | unsigned long flags; | |
154 | u32 data; | |
155 | ||
156 | if (gpio > 15 || gpio < 0) | |
157 | return -EINVAL; | |
158 | ||
159 | spin_lock_irqsave(&gpio_lock, flags); | |
160 | ||
161 | data = __raw_readl((void __iomem *)(MSP71XX_GPIO_BASE + 0x190)); | |
162 | if (value) | |
163 | data |= (1 << gpio); | |
164 | else | |
165 | data &= ~(1 << gpio); | |
166 | __raw_writel(data, (void __iomem *)(MSP71XX_GPIO_BASE + 0x190)); | |
167 | ||
168 | spin_unlock_irqrestore(&gpio_lock, flags); | |
169 | ||
170 | return 0; | |
171 | } | |
172 | EXPORT_SYMBOL(msp71xx_set_output_drive); | |
173 | ||
174 | #define MSP71XX_GPIO_BANK(name, dr, cr, base_gpio, num_gpio) \ | |
175 | { \ | |
176 | .chip = { \ | |
177 | .label = name, \ | |
178 | .direction_input = msp71xx_direction_input, \ | |
179 | .direction_output = msp71xx_direction_output, \ | |
180 | .get = msp71xx_gpio_get, \ | |
181 | .set = msp71xx_gpio_set, \ | |
182 | .base = base_gpio, \ | |
183 | .ngpio = num_gpio \ | |
184 | }, \ | |
185 | .data_reg = (void __iomem *)(MSP71XX_GPIO_BASE + dr), \ | |
186 | .config_reg = (void __iomem *)(MSP71XX_GPIO_BASE + cr), \ | |
187 | .out_drive_reg = (void __iomem *)(MSP71XX_GPIO_BASE + 0x190), \ | |
188 | } | |
189 | ||
190 | /* | |
191 | * struct msp71xx_gpio_banks[] - container array of gpio banks | |
192 | * @chip: chip structure for the specified gpio bank | |
193 | * @data_reg: register for reading and writing the gpio pin value | |
194 | * @config_reg: register to set the mode for the gpio pin bank | |
195 | * | |
196 | * This array structure defines the gpio banks for the PMC MIPS Processor. | |
197 | * We specify the bank name, the data register, the config register, base | |
198 | * starting gpio number, and the number of gpios exposed by the bank. | |
199 | */ | |
200 | static struct msp71xx_gpio_chip msp71xx_gpio_banks[] = { | |
201 | ||
202 | MSP71XX_GPIO_BANK("GPIO_1_0", 0x170, 0x180, 0, 2), | |
203 | MSP71XX_GPIO_BANK("GPIO_5_2", 0x174, 0x184, 2, 4), | |
204 | MSP71XX_GPIO_BANK("GPIO_9_6", 0x178, 0x188, 6, 4), | |
205 | MSP71XX_GPIO_BANK("GPIO_15_10", 0x17C, 0x18C, 10, 6), | |
206 | }; | |
207 | ||
208 | void __init msp71xx_init_gpio(void) | |
209 | { | |
210 | int i; | |
211 | ||
212 | spin_lock_init(&gpio_lock); | |
213 | ||
214 | for (i = 0; i < ARRAY_SIZE(msp71xx_gpio_banks); i++) | |
215 | gpiochip_add(&msp71xx_gpio_banks[i].chip); | |
216 | } |