Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
via-gpio.c
Go to the documentation of this file.
1 /*
2  * Support for viafb GPIO ports.
3  *
4  * Copyright 2009 Jonathan Corbet <[email protected]>
5  * Distributable under version 2 of the GNU General Public License.
6  */
7 
8 #include <linux/spinlock.h>
9 #include <linux/gpio.h>
10 #include <linux/platform_device.h>
11 #include <linux/via-core.h>
12 #include <linux/via-gpio.h>
13 #include <linux/export.h>
14 
15 /*
16  * The ports we know about. Note that the port-25 gpios are not
17  * mentioned in the datasheet.
18  */
19 
20 struct viafb_gpio {
21  char *vg_name; /* Data sheet name */
25 };
26 
27 static struct viafb_gpio viafb_all_gpios[] = {
28  {
29  .vg_name = "VGPIO0", /* Guess - not in datasheet */
30  .vg_io_port = VIASR,
31  .vg_port_index = 0x25,
32  .vg_mask_shift = 1
33  },
34  {
35  .vg_name = "VGPIO1",
36  .vg_io_port = VIASR,
37  .vg_port_index = 0x25,
38  .vg_mask_shift = 0
39  },
40  {
41  .vg_name = "VGPIO2", /* aka DISPCLKI0 */
42  .vg_io_port = VIASR,
43  .vg_port_index = 0x2c,
44  .vg_mask_shift = 1
45  },
46  {
47  .vg_name = "VGPIO3", /* aka DISPCLKO0 */
48  .vg_io_port = VIASR,
49  .vg_port_index = 0x2c,
50  .vg_mask_shift = 0
51  },
52  {
53  .vg_name = "VGPIO4", /* DISPCLKI1 */
54  .vg_io_port = VIASR,
55  .vg_port_index = 0x3d,
56  .vg_mask_shift = 1
57  },
58  {
59  .vg_name = "VGPIO5", /* DISPCLKO1 */
60  .vg_io_port = VIASR,
61  .vg_port_index = 0x3d,
62  .vg_mask_shift = 0
63  },
64 };
65 
66 #define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios)
67 
68 /*
69  * This structure controls the active GPIOs, which may be a subset
70  * of those which are known.
71  */
72 
75  struct viafb_dev *vdev;
78 };
79 
80 /*
81  * GPIO access functions
82  */
83 static void via_gpio_set(struct gpio_chip *chip, unsigned int nr,
84  int value)
85 {
86  struct viafb_gpio_cfg *cfg = container_of(chip,
87  struct viafb_gpio_cfg,
88  gpio_chip);
89  u8 reg;
90  struct viafb_gpio *gpio;
91  unsigned long flags;
92 
93  spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
94  gpio = cfg->active_gpios[nr];
95  reg = via_read_reg(VIASR, gpio->vg_port_index);
96  reg |= 0x40 << gpio->vg_mask_shift; /* output enable */
97  if (value)
98  reg |= 0x10 << gpio->vg_mask_shift;
99  else
100  reg &= ~(0x10 << gpio->vg_mask_shift);
101  via_write_reg(VIASR, gpio->vg_port_index, reg);
102  spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
103 }
104 
105 static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr,
106  int value)
107 {
108  via_gpio_set(chip, nr, value);
109  return 0;
110 }
111 
112 /*
113  * Set the input direction. I'm not sure this is right; we should
114  * be able to do input without disabling output.
115  */
116 static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
117 {
118  struct viafb_gpio_cfg *cfg = container_of(chip,
119  struct viafb_gpio_cfg,
120  gpio_chip);
121  struct viafb_gpio *gpio;
122  unsigned long flags;
123 
124  spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
125  gpio = cfg->active_gpios[nr];
126  via_write_reg_mask(VIASR, gpio->vg_port_index, 0,
127  0x40 << gpio->vg_mask_shift);
128  spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
129  return 0;
130 }
131 
132 static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
133 {
134  struct viafb_gpio_cfg *cfg = container_of(chip,
135  struct viafb_gpio_cfg,
136  gpio_chip);
137  u8 reg;
138  struct viafb_gpio *gpio;
139  unsigned long flags;
140 
141  spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
142  gpio = cfg->active_gpios[nr];
143  reg = via_read_reg(VIASR, gpio->vg_port_index);
144  spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
145  return reg & (0x04 << gpio->vg_mask_shift);
146 }
147 
148 
149 static struct viafb_gpio_cfg viafb_gpio_config = {
150  .gpio_chip = {
151  .label = "VIAFB onboard GPIO",
152  .owner = THIS_MODULE,
153  .direction_output = via_gpio_dir_out,
154  .set = via_gpio_set,
155  .direction_input = via_gpio_dir_input,
156  .get = via_gpio_get,
157  .base = -1,
158  .ngpio = 0,
159  .can_sleep = 0
160  }
161 };
162 
163 /*
164  * Manage the software enable bit.
165  */
166 static void viafb_gpio_enable(struct viafb_gpio *gpio)
167 {
168  via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02);
169 }
170 
171 static void viafb_gpio_disable(struct viafb_gpio *gpio)
172 {
173  via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
174 }
175 
176 #ifdef CONFIG_PM
177 
178 static int viafb_gpio_suspend(void *private)
179 {
180  return 0;
181 }
182 
183 static int viafb_gpio_resume(void *private)
184 {
185  int i;
186 
187  for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
188  viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
189  return 0;
190 }
191 
192 static struct viafb_pm_hooks viafb_gpio_pm_hooks = {
193  .suspend = viafb_gpio_suspend,
194  .resume = viafb_gpio_resume
195 };
196 #endif /* CONFIG_PM */
197 
198 /*
199  * Look up a specific gpio and return the number it was assigned.
200  */
201 int viafb_gpio_lookup(const char *name)
202 {
203  int i;
204 
205  for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i++)
206  if (!strcmp(name, viafb_gpio_config.active_gpios[i]->vg_name))
207  return viafb_gpio_config.gpio_chip.base + i;
208  return -1;
209 }
211 
212 /*
213  * Platform device stuff.
214  */
215 static __devinit int viafb_gpio_probe(struct platform_device *platdev)
216 {
217  struct viafb_dev *vdev = platdev->dev.platform_data;
218  struct via_port_cfg *port_cfg = vdev->port_cfg;
219  int i, ngpio = 0, ret;
220  struct viafb_gpio *gpio;
221  unsigned long flags;
222 
223  /*
224  * Set up entries for all GPIOs which have been configured to
225  * operate as such (as opposed to as i2c ports).
226  */
227  for (i = 0; i < VIAFB_NUM_PORTS; i++) {
228  if (port_cfg[i].mode != VIA_MODE_GPIO)
229  continue;
230  for (gpio = viafb_all_gpios;
231  gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++)
232  if (gpio->vg_port_index == port_cfg[i].ioport_index) {
233  viafb_gpio_config.active_gpios[ngpio] = gpio;
234  viafb_gpio_config.gpio_names[ngpio] =
235  gpio->vg_name;
236  ngpio++;
237  }
238  }
239  viafb_gpio_config.gpio_chip.ngpio = ngpio;
240  viafb_gpio_config.gpio_chip.names = viafb_gpio_config.gpio_names;
241  viafb_gpio_config.vdev = vdev;
242  if (ngpio == 0) {
243  printk(KERN_INFO "viafb: no GPIOs configured\n");
244  return 0;
245  }
246  /*
247  * Enable the ports. They come in pairs, with a single
248  * enable bit for both.
249  */
250  spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
251  for (i = 0; i < ngpio; i += 2)
252  viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
253  spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
254  /*
255  * Get registered.
256  */
257  viafb_gpio_config.gpio_chip.base = -1; /* Dynamic */
258  ret = gpiochip_add(&viafb_gpio_config.gpio_chip);
259  if (ret) {
260  printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
261  viafb_gpio_config.gpio_chip.ngpio = 0;
262  }
263 #ifdef CONFIG_PM
264  viafb_pm_register(&viafb_gpio_pm_hooks);
265 #endif
266  return ret;
267 }
268 
269 
270 static int viafb_gpio_remove(struct platform_device *platdev)
271 {
272  unsigned long flags;
273  int ret = 0, i;
274 
275 #ifdef CONFIG_PM
276  viafb_pm_unregister(&viafb_gpio_pm_hooks);
277 #endif
278 
279  /*
280  * Get unregistered.
281  */
282  if (viafb_gpio_config.gpio_chip.ngpio > 0) {
283  ret = gpiochip_remove(&viafb_gpio_config.gpio_chip);
284  if (ret) { /* Somebody still using it? */
285  printk(KERN_ERR "Viafb: GPIO remove failed\n");
286  return ret;
287  }
288  }
289  /*
290  * Disable the ports.
291  */
292  spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
293  for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
294  viafb_gpio_disable(viafb_gpio_config.active_gpios[i]);
295  viafb_gpio_config.gpio_chip.ngpio = 0;
296  spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
297  return ret;
298 }
299 
300 static struct platform_driver via_gpio_driver = {
301  .driver = {
302  .name = "viafb-gpio",
303  },
304  .probe = viafb_gpio_probe,
305  .remove = viafb_gpio_remove,
306 };
307 
309 {
310  return platform_driver_register(&via_gpio_driver);
311 }
312 
313 void viafb_gpio_exit(void)
314 {
315  platform_driver_unregister(&via_gpio_driver);
316 }