]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/sh/pfc/gpio.c
Merge remote-tracking branch 'regulator/topic/max8997' into regulator-next
[karo-tx-linux.git] / drivers / sh / pfc / gpio.c
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;
24         struct gpio_chip        gpio_chip;
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
139 int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
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 }
161 EXPORT_SYMBOL_GPL(sh_pfc_register_gpiochip);
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 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 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         = 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");