diff options
Diffstat (limited to 'arch/powerpc/sysdev/cpm_common.c')
-rw-r--r-- | arch/powerpc/sysdev/cpm_common.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index e4b7296acb2c..53da8a079f96 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c | |||
@@ -19,6 +19,8 @@ | |||
19 | 19 | ||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/of_device.h> | 21 | #include <linux/of_device.h> |
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/of.h> | ||
22 | 24 | ||
23 | #include <asm/udbg.h> | 25 | #include <asm/udbg.h> |
24 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -28,6 +30,10 @@ | |||
28 | 30 | ||
29 | #include <mm/mmu_decl.h> | 31 | #include <mm/mmu_decl.h> |
30 | 32 | ||
33 | #if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO) | ||
34 | #include <linux/of_gpio.h> | ||
35 | #endif | ||
36 | |||
31 | #ifdef CONFIG_PPC_EARLY_DEBUG_CPM | 37 | #ifdef CONFIG_PPC_EARLY_DEBUG_CPM |
32 | static u32 __iomem *cpm_udbg_txdesc = | 38 | static u32 __iomem *cpm_udbg_txdesc = |
33 | (u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR; | 39 | (u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR; |
@@ -207,3 +213,120 @@ dma_addr_t cpm_muram_dma(void __iomem *addr) | |||
207 | return muram_pbase + ((u8 __iomem *)addr - muram_vbase); | 213 | return muram_pbase + ((u8 __iomem *)addr - muram_vbase); |
208 | } | 214 | } |
209 | EXPORT_SYMBOL(cpm_muram_dma); | 215 | EXPORT_SYMBOL(cpm_muram_dma); |
216 | |||
217 | #if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO) | ||
218 | |||
219 | struct cpm2_ioports { | ||
220 | u32 dir, par, sor, odr, dat; | ||
221 | u32 res[3]; | ||
222 | }; | ||
223 | |||
224 | struct cpm2_gpio32_chip { | ||
225 | struct of_mm_gpio_chip mm_gc; | ||
226 | spinlock_t lock; | ||
227 | |||
228 | /* shadowed data register to clear/set bits safely */ | ||
229 | u32 cpdata; | ||
230 | }; | ||
231 | |||
232 | static inline struct cpm2_gpio32_chip * | ||
233 | to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc) | ||
234 | { | ||
235 | return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc); | ||
236 | } | ||
237 | |||
238 | static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
239 | { | ||
240 | struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); | ||
241 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
242 | |||
243 | cpm2_gc->cpdata = in_be32(&iop->dat); | ||
244 | } | ||
245 | |||
246 | static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio) | ||
247 | { | ||
248 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
249 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
250 | u32 pin_mask; | ||
251 | |||
252 | pin_mask = 1 << (31 - gpio); | ||
253 | |||
254 | return !!(in_be32(&iop->dat) & pin_mask); | ||
255 | } | ||
256 | |||
257 | static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
258 | { | ||
259 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
260 | struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); | ||
261 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
262 | unsigned long flags; | ||
263 | u32 pin_mask = 1 << (31 - gpio); | ||
264 | |||
265 | spin_lock_irqsave(&cpm2_gc->lock, flags); | ||
266 | |||
267 | if (value) | ||
268 | cpm2_gc->cpdata |= pin_mask; | ||
269 | else | ||
270 | cpm2_gc->cpdata &= ~pin_mask; | ||
271 | |||
272 | out_be32(&iop->dat, cpm2_gc->cpdata); | ||
273 | |||
274 | spin_unlock_irqrestore(&cpm2_gc->lock, flags); | ||
275 | } | ||
276 | |||
277 | static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
278 | { | ||
279 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
280 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
281 | u32 pin_mask; | ||
282 | |||
283 | pin_mask = 1 << (31 - gpio); | ||
284 | |||
285 | setbits32(&iop->dir, pin_mask); | ||
286 | |||
287 | cpm2_gpio32_set(gc, gpio, val); | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
293 | { | ||
294 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
295 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
296 | u32 pin_mask; | ||
297 | |||
298 | pin_mask = 1 << (31 - gpio); | ||
299 | |||
300 | clrbits32(&iop->dir, pin_mask); | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | int cpm2_gpiochip_add32(struct device_node *np) | ||
306 | { | ||
307 | struct cpm2_gpio32_chip *cpm2_gc; | ||
308 | struct of_mm_gpio_chip *mm_gc; | ||
309 | struct of_gpio_chip *of_gc; | ||
310 | struct gpio_chip *gc; | ||
311 | |||
312 | cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL); | ||
313 | if (!cpm2_gc) | ||
314 | return -ENOMEM; | ||
315 | |||
316 | spin_lock_init(&cpm2_gc->lock); | ||
317 | |||
318 | mm_gc = &cpm2_gc->mm_gc; | ||
319 | of_gc = &mm_gc->of_gc; | ||
320 | gc = &of_gc->gc; | ||
321 | |||
322 | mm_gc->save_regs = cpm2_gpio32_save_regs; | ||
323 | of_gc->gpio_cells = 2; | ||
324 | gc->ngpio = 32; | ||
325 | gc->direction_input = cpm2_gpio32_dir_in; | ||
326 | gc->direction_output = cpm2_gpio32_dir_out; | ||
327 | gc->get = cpm2_gpio32_get; | ||
328 | gc->set = cpm2_gpio32_set; | ||
329 | |||
330 | return of_mm_gpiochip_add(np, mm_gc); | ||
331 | } | ||
332 | #endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */ | ||