Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gpio.c
Go to the documentation of this file.
1 /*
2  * SuperH Pin Function Controller GPIO driver.
3  *
4  * Copyright (C) 2008 Magnus Damm
5  * Copyright (C) 2009 - 2012 Paul Mundt
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License. See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11 #define pr_fmt(fmt) "sh_pfc " KBUILD_MODNAME ": " fmt
12 
13 #include <linux/init.h>
14 #include <linux/gpio.h>
15 #include <linux/slab.h>
16 #include <linux/spinlock.h>
17 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/pinctrl/consumer.h>
20 #include <linux/sh_pfc.h>
21 
22 struct sh_pfc_chip {
23  struct sh_pfc *pfc;
25 };
26 
27 static struct sh_pfc_chip *gpio_to_pfc_chip(struct gpio_chip *gc)
28 {
29  return container_of(gc, struct sh_pfc_chip, gpio_chip);
30 }
31 
32 static struct sh_pfc *gpio_to_pfc(struct gpio_chip *gc)
33 {
34  return gpio_to_pfc_chip(gc)->pfc;
35 }
36 
37 static int sh_gpio_request(struct gpio_chip *gc, unsigned offset)
38 {
39  return pinctrl_request_gpio(offset);
40 }
41 
42 static void sh_gpio_free(struct gpio_chip *gc, unsigned offset)
43 {
44  pinctrl_free_gpio(offset);
45 }
46 
47 static void sh_gpio_set_value(struct sh_pfc *pfc, unsigned gpio, int value)
48 {
49  struct pinmux_data_reg *dr = NULL;
50  int bit = 0;
51 
52  if (!pfc || sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
53  BUG();
54  else
55  sh_pfc_write_bit(dr, bit, value);
56 }
57 
58 static int sh_gpio_get_value(struct sh_pfc *pfc, unsigned gpio)
59 {
60  struct pinmux_data_reg *dr = NULL;
61  int bit = 0;
62 
63  if (!pfc || sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
64  return -EINVAL;
65 
66  return sh_pfc_read_bit(dr, bit);
67 }
68 
69 static int sh_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
70 {
71  return pinctrl_gpio_direction_input(offset);
72 }
73 
74 static int sh_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
75  int value)
76 {
77  sh_gpio_set_value(gpio_to_pfc(gc), offset, value);
78 
79  return pinctrl_gpio_direction_output(offset);
80 }
81 
82 static int sh_gpio_get(struct gpio_chip *gc, unsigned offset)
83 {
84  return sh_gpio_get_value(gpio_to_pfc(gc), offset);
85 }
86 
87 static void sh_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
88 {
89  sh_gpio_set_value(gpio_to_pfc(gc), offset, value);
90 }
91 
92 static int sh_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
93 {
94  struct sh_pfc *pfc = gpio_to_pfc(gc);
95  pinmux_enum_t enum_id;
96  pinmux_enum_t *enum_ids;
97  int i, k, pos;
98 
99  pos = 0;
100  enum_id = 0;
101  while (1) {
102  pos = sh_pfc_gpio_to_enum(pfc, offset, pos, &enum_id);
103  if (pos <= 0 || !enum_id)
104  break;
105 
106  for (i = 0; i < pfc->gpio_irq_size; i++) {
107  enum_ids = pfc->gpio_irq[i].enum_ids;
108  for (k = 0; enum_ids[k]; k++) {
109  if (enum_ids[k] == enum_id)
110  return pfc->gpio_irq[i].irq;
111  }
112  }
113  }
114 
115  return -ENOSYS;
116 }
117 
118 static void sh_pfc_gpio_setup(struct sh_pfc_chip *chip)
119 {
120  struct sh_pfc *pfc = chip->pfc;
121  struct gpio_chip *gc = &chip->gpio_chip;
122 
123  gc->request = sh_gpio_request;
124  gc->free = sh_gpio_free;
125  gc->direction_input = sh_gpio_direction_input;
126  gc->get = sh_gpio_get;
127  gc->direction_output = sh_gpio_direction_output;
128  gc->set = sh_gpio_set;
129  gc->to_irq = sh_gpio_to_irq;
130 
131  WARN_ON(pfc->first_gpio != 0); /* needs testing */
132 
133  gc->label = pfc->name;
134  gc->owner = THIS_MODULE;
135  gc->base = pfc->first_gpio;
136  gc->ngpio = (pfc->last_gpio - pfc->first_gpio) + 1;
137 }
138 
140 {
141  struct sh_pfc_chip *chip;
142  int ret;
143 
144  chip = kzalloc(sizeof(struct sh_pfc_chip), GFP_KERNEL);
145  if (unlikely(!chip))
146  return -ENOMEM;
147 
148  chip->pfc = pfc;
149 
150  sh_pfc_gpio_setup(chip);
151 
152  ret = gpiochip_add(&chip->gpio_chip);
153  if (unlikely(ret < 0))
154  kfree(chip);
155 
156  pr_info("%s handling gpio %d -> %d\n",
157  pfc->name, pfc->first_gpio, pfc->last_gpio);
158 
159  return ret;
160 }
162 
163 static int sh_pfc_gpio_match(struct gpio_chip *gc, void *data)
164 {
165  return !!strstr(gc->label, data);
166 }
167 
168 static int __devinit sh_pfc_gpio_probe(struct platform_device *pdev)
169 {
170  struct sh_pfc_chip *chip;
171  struct gpio_chip *gc;
172 
173  gc = gpiochip_find("_pfc", sh_pfc_gpio_match);
174  if (unlikely(!gc)) {
175  pr_err("Cant find gpio chip\n");
176  return -ENODEV;
177  }
178 
179  chip = gpio_to_pfc_chip(gc);
180  platform_set_drvdata(pdev, chip);
181 
182  pr_info("attaching to GPIO chip %s\n", chip->pfc->name);
183 
184  return 0;
185 }
186 
187 static int __devexit sh_pfc_gpio_remove(struct platform_device *pdev)
188 {
189  struct sh_pfc_chip *chip = platform_get_drvdata(pdev);
190  int ret;
191 
192  ret = gpiochip_remove(&chip->gpio_chip);
193  if (unlikely(ret < 0))
194  return ret;
195 
196  kfree(chip);
197  return 0;
198 }
199 
200 static struct platform_driver sh_pfc_gpio_driver = {
201  .probe = sh_pfc_gpio_probe,
202  .remove = __devexit_p(sh_pfc_gpio_remove),
203  .driver = {
204  .name = KBUILD_MODNAME,
205  .owner = THIS_MODULE,
206  },
207 };
208 
209 static struct platform_device sh_pfc_gpio_device = {
210  .name = KBUILD_MODNAME,
211  .id = -1,
212 };
213 
214 static int __init sh_pfc_gpio_init(void)
215 {
216  int rc;
217 
218  rc = platform_driver_register(&sh_pfc_gpio_driver);
219  if (likely(!rc)) {
220  rc = platform_device_register(&sh_pfc_gpio_device);
221  if (unlikely(rc))
222  platform_driver_unregister(&sh_pfc_gpio_driver);
223  }
224 
225  return rc;
226 }
227 
228 static void __exit sh_pfc_gpio_exit(void)
229 {
230  platform_device_unregister(&sh_pfc_gpio_device);
231  platform_driver_unregister(&sh_pfc_gpio_driver);
232 }
233 
234 module_init(sh_pfc_gpio_init);
235 module_exit(sh_pfc_gpio_exit);
236 
237 MODULE_AUTHOR("Magnus Damm, Paul Mundt");
238 MODULE_DESCRIPTION("GPIO driver for SuperH pin function controller");
239 MODULE_LICENSE("GPL v2");
240 MODULE_ALIAS("platform:pfc-gpio");