Blame view

arch/powerpc/sysdev/simple_gpio.c 3.21 KB
3d64de9c5   Anton Vorontsov   powerpc: Implemen...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * Simple Memory-Mapped GPIOs
   *
   * Copyright (c) MontaVista Software, Inc. 2008.
   *
   * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
   *
   * 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.
   */
  
  #include <linux/init.h>
  #include <linux/kernel.h>
3d64de9c5   Anton Vorontsov   powerpc: Implemen...
16
17
18
19
20
21
22
  #include <linux/spinlock.h>
  #include <linux/types.h>
  #include <linux/ioport.h>
  #include <linux/io.h>
  #include <linux/of.h>
  #include <linux/of_gpio.h>
  #include <linux/gpio.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
23
  #include <linux/slab.h>
3d64de9c5   Anton Vorontsov   powerpc: Implemen...
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
  #include <asm/prom.h>
  #include "simple_gpio.h"
  
  struct u8_gpio_chip {
  	struct of_mm_gpio_chip mm_gc;
  	spinlock_t lock;
  
  	/* shadowed data register to clear/set bits safely */
  	u8 data;
  };
  
  static struct u8_gpio_chip *to_u8_gpio_chip(struct of_mm_gpio_chip *mm_gc)
  {
  	return container_of(mm_gc, struct u8_gpio_chip, mm_gc);
  }
  
  static u8 u8_pin2mask(unsigned int pin)
  {
  	return 1 << (8 - 1 - pin);
  }
  
  static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
  
  	return in_8(mm_gc->regs) & u8_pin2mask(gpio);
  }
  
  static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
  	struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc);
  	unsigned long flags;
  
  	spin_lock_irqsave(&u8_gc->lock, flags);
  
  	if (val)
  		u8_gc->data |= u8_pin2mask(gpio);
  	else
  		u8_gc->data &= ~u8_pin2mask(gpio);
  
  	out_8(mm_gc->regs, u8_gc->data);
  
  	spin_unlock_irqrestore(&u8_gc->lock, flags);
  }
  
  static int u8_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
  {
  	return 0;
  }
  
  static int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
  {
  	u8_gpio_set(gc, gpio, val);
  	return 0;
  }
  
  static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
  {
  	struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc);
  
  	u8_gc->data = in_8(mm_gc->regs);
  }
  
  static int __init u8_simple_gpiochip_add(struct device_node *np)
  {
  	int ret;
  	struct u8_gpio_chip *u8_gc;
  	struct of_mm_gpio_chip *mm_gc;
3d64de9c5   Anton Vorontsov   powerpc: Implemen...
93
94
95
96
97
98
99
100
101
  	struct gpio_chip *gc;
  
  	u8_gc = kzalloc(sizeof(*u8_gc), GFP_KERNEL);
  	if (!u8_gc)
  		return -ENOMEM;
  
  	spin_lock_init(&u8_gc->lock);
  
  	mm_gc = &u8_gc->mm_gc;
a19e3da5b   Anton Vorontsov   of/gpio: Kill of_...
102
  	gc = &mm_gc->gc;
3d64de9c5   Anton Vorontsov   powerpc: Implemen...
103
104
  
  	mm_gc->save_regs = u8_gpio_save_regs;
3d64de9c5   Anton Vorontsov   powerpc: Implemen...
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
  	gc->ngpio = 8;
  	gc->direction_input = u8_gpio_dir_in;
  	gc->direction_output = u8_gpio_dir_out;
  	gc->get = u8_gpio_get;
  	gc->set = u8_gpio_set;
  
  	ret = of_mm_gpiochip_add(np, mm_gc);
  	if (ret)
  		goto err;
  	return 0;
  err:
  	kfree(u8_gc);
  	return ret;
  }
  
  void __init simple_gpiochip_init(const char *compatible)
  {
  	struct device_node *np;
  
  	for_each_compatible_node(np, NULL, compatible) {
  		int ret;
  		struct resource r;
  
  		ret = of_address_to_resource(np, 0, &r);
  		if (ret)
  			goto err;
  
  		switch (resource_size(&r)) {
  		case 1:
  			ret = u8_simple_gpiochip_add(np);
  			if (ret)
  				goto err;
  			break;
  		default:
  			/*
  			 * Whenever you need support for GPIO bank width > 1,
  			 * please just turn u8_ code into huge macros, and
  			 * construct needed uX_ code with it.
  			 */
  			ret = -ENOSYS;
  			goto err;
  		}
  		continue;
  err:
  		pr_err("%s: registration failed, status %d
  ",
  		       np->full_name, ret);
  	}
  }