blob: 1f73dd25665aab83d706e414a8d7a7e33335323f [file] [log] [blame]
Thomas Abraham30574f02012-09-07 06:07:19 +09001/*
2 * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's.
3 *
4 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com
6 * Copyright (c) 2012 Linaro Ltd
7 * http://www.linaro.org
8 *
9 * Author: Thomas Abraham <thomas.ab@samsung.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver implements the Samsung pinctrl driver. It supports setting up of
17 * pinmux and pinconf configurations. The gpiolib interface is also included.
18 * External interrupt (gpio and wakeup) support are not included in this driver
19 * but provides extensions to which platform specific implementation of the gpio
20 * and wakeup interrupts can be hooked to.
21 */
22
Paul Gortmaker8208b282017-05-22 16:56:46 -040023#include <linux/init.h>
Thomas Abraham30574f02012-09-07 06:07:19 +090024#include <linux/platform_device.h>
25#include <linux/io.h>
26#include <linux/slab.h>
27#include <linux/err.h>
28#include <linux/gpio.h>
Tomasz Figaa19fe2d2012-10-11 10:11:20 +020029#include <linux/irqdomain.h>
Marek Szyprowski9abc2b92017-01-26 10:29:23 +010030#include <linux/of_device.h>
Tomasz Figa19846952013-03-18 22:31:50 +010031#include <linux/spinlock.h>
Thomas Abraham30574f02012-09-07 06:07:19 +090032
Krzysztof Kozlowski4460dc22017-06-15 17:06:28 +020033#include <dt-bindings/pinctrl/samsung.h>
34
Sachin Kamatebe629a2014-07-10 17:33:27 +053035#include "../core.h"
Thomas Abraham30574f02012-09-07 06:07:19 +090036#include "pinctrl-samsung.h"
37
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +090038/* maximum number of the memory resources */
39#define SAMSUNG_PINCTRL_NUM_RESOURCES 2
40
Thomas Abraham30574f02012-09-07 06:07:19 +090041/* list of all possible config options supported */
Axel Lind5fd5da2012-12-10 09:54:03 +090042static struct pin_config {
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020043 const char *property;
44 enum pincfg_type param;
45} cfg_params[] = {
Thomas Abraham30574f02012-09-07 06:07:19 +090046 { "samsung,pin-pud", PINCFG_TYPE_PUD },
47 { "samsung,pin-drv", PINCFG_TYPE_DRV },
48 { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN },
49 { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN },
Tomasz Figa2700bc02014-07-02 17:41:04 +020050 { "samsung,pin-val", PINCFG_TYPE_DAT },
Thomas Abraham30574f02012-09-07 06:07:19 +090051};
52
Sachin Kamat6fb6f1ba2012-11-24 11:20:51 +090053static unsigned int pin_base;
Tomasz Figa40ba6222012-10-11 10:11:09 +020054
Thomas Abraham30574f02012-09-07 06:07:19 +090055static int samsung_get_group_count(struct pinctrl_dev *pctldev)
56{
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020057 struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
Thomas Abraham30574f02012-09-07 06:07:19 +090058
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020059 return pmx->nr_groups;
Thomas Abraham30574f02012-09-07 06:07:19 +090060}
61
Thomas Abraham30574f02012-09-07 06:07:19 +090062static const char *samsung_get_group_name(struct pinctrl_dev *pctldev,
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020063 unsigned group)
Thomas Abraham30574f02012-09-07 06:07:19 +090064{
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020065 struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
Thomas Abraham30574f02012-09-07 06:07:19 +090066
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020067 return pmx->pin_groups[group].name;
Thomas Abraham30574f02012-09-07 06:07:19 +090068}
69
Thomas Abraham30574f02012-09-07 06:07:19 +090070static int samsung_get_group_pins(struct pinctrl_dev *pctldev,
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020071 unsigned group,
72 const unsigned **pins,
73 unsigned *num_pins)
Thomas Abraham30574f02012-09-07 06:07:19 +090074{
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020075 struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
Thomas Abraham30574f02012-09-07 06:07:19 +090076
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020077 *pins = pmx->pin_groups[group].pins;
78 *num_pins = pmx->pin_groups[group].num_pins;
79
Thomas Abraham30574f02012-09-07 06:07:19 +090080 return 0;
81}
82
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020083static int reserve_map(struct device *dev, struct pinctrl_map **map,
84 unsigned *reserved_maps, unsigned *num_maps,
85 unsigned reserve)
Thomas Abraham30574f02012-09-07 06:07:19 +090086{
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020087 unsigned old_num = *reserved_maps;
88 unsigned new_num = *num_maps + reserve;
89 struct pinctrl_map *new_map;
Thomas Abraham30574f02012-09-07 06:07:19 +090090
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020091 if (old_num >= new_num)
92 return 0;
Thomas Abraham30574f02012-09-07 06:07:19 +090093
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020094 new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
Marek Szyprowskifa5c0f42017-01-19 14:48:45 +010095 if (!new_map)
Thomas Abraham30574f02012-09-07 06:07:19 +090096 return -ENOMEM;
Thomas Abraham30574f02012-09-07 06:07:19 +090097
Tomasz Figa9a2c1c32014-07-02 17:41:03 +020098 memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
Thomas Abraham30574f02012-09-07 06:07:19 +090099
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200100 *map = new_map;
101 *reserved_maps = new_num;
Thomas Abraham30574f02012-09-07 06:07:19 +0900102
Thomas Abraham30574f02012-09-07 06:07:19 +0900103 return 0;
Thomas Abraham30574f02012-09-07 06:07:19 +0900104}
105
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200106static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
107 unsigned *num_maps, const char *group,
108 const char *function)
Thomas Abraham30574f02012-09-07 06:07:19 +0900109{
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200110 if (WARN_ON(*num_maps == *reserved_maps))
111 return -ENOSPC;
Thomas Abraham30574f02012-09-07 06:07:19 +0900112
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200113 (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
114 (*map)[*num_maps].data.mux.group = group;
115 (*map)[*num_maps].data.mux.function = function;
116 (*num_maps)++;
117
118 return 0;
119}
120
121static int add_map_configs(struct device *dev, struct pinctrl_map **map,
122 unsigned *reserved_maps, unsigned *num_maps,
123 const char *group, unsigned long *configs,
124 unsigned num_configs)
125{
126 unsigned long *dup_configs;
127
128 if (WARN_ON(*num_maps == *reserved_maps))
129 return -ENOSPC;
130
131 dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
132 GFP_KERNEL);
Marek Szyprowskifa5c0f42017-01-19 14:48:45 +0100133 if (!dup_configs)
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200134 return -ENOMEM;
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200135
136 (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
137 (*map)[*num_maps].data.configs.group_or_pin = group;
138 (*map)[*num_maps].data.configs.configs = dup_configs;
139 (*map)[*num_maps].data.configs.num_configs = num_configs;
140 (*num_maps)++;
141
142 return 0;
143}
144
145static int add_config(struct device *dev, unsigned long **configs,
146 unsigned *num_configs, unsigned long config)
147{
148 unsigned old_num = *num_configs;
149 unsigned new_num = old_num + 1;
150 unsigned long *new_configs;
151
152 new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
153 GFP_KERNEL);
Marek Szyprowskifa5c0f42017-01-19 14:48:45 +0100154 if (!new_configs)
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200155 return -ENOMEM;
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200156
157 new_configs[old_num] = config;
158
159 *configs = new_configs;
160 *num_configs = new_num;
161
162 return 0;
163}
164
165static void samsung_dt_free_map(struct pinctrl_dev *pctldev,
166 struct pinctrl_map *map,
167 unsigned num_maps)
168{
169 int i;
170
171 for (i = 0; i < num_maps; i++)
172 if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
173 kfree(map[i].data.configs.configs);
Thomas Abraham30574f02012-09-07 06:07:19 +0900174
175 kfree(map);
176}
177
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200178static int samsung_dt_subnode_to_map(struct samsung_pinctrl_drv_data *drvdata,
179 struct device *dev,
180 struct device_node *np,
181 struct pinctrl_map **map,
182 unsigned *reserved_maps,
183 unsigned *num_maps)
184{
185 int ret, i;
186 u32 val;
187 unsigned long config;
188 unsigned long *configs = NULL;
189 unsigned num_configs = 0;
190 unsigned reserve;
191 struct property *prop;
192 const char *group;
193 bool has_func = false;
194
195 ret = of_property_read_u32(np, "samsung,pin-function", &val);
196 if (!ret)
197 has_func = true;
198
199 for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
200 ret = of_property_read_u32(np, cfg_params[i].property, &val);
201 if (!ret) {
202 config = PINCFG_PACK(cfg_params[i].param, val);
203 ret = add_config(dev, &configs, &num_configs, config);
204 if (ret < 0)
205 goto exit;
206 /* EINVAL=missing, which is fine since it's optional */
207 } else if (ret != -EINVAL) {
208 dev_err(dev, "could not parse property %s\n",
209 cfg_params[i].property);
210 }
211 }
212
213 reserve = 0;
214 if (has_func)
215 reserve++;
216 if (num_configs)
217 reserve++;
218 ret = of_property_count_strings(np, "samsung,pins");
219 if (ret < 0) {
220 dev_err(dev, "could not parse property samsung,pins\n");
221 goto exit;
222 }
223 reserve *= ret;
224
225 ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
226 if (ret < 0)
227 goto exit;
228
229 of_property_for_each_string(np, "samsung,pins", prop, group) {
230 if (has_func) {
231 ret = add_map_mux(map, reserved_maps,
232 num_maps, group, np->full_name);
233 if (ret < 0)
234 goto exit;
235 }
236
237 if (num_configs) {
238 ret = add_map_configs(dev, map, reserved_maps,
239 num_maps, group, configs,
240 num_configs);
241 if (ret < 0)
242 goto exit;
243 }
244 }
245
246 ret = 0;
247
248exit:
249 kfree(configs);
250 return ret;
251}
252
253static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev,
254 struct device_node *np_config,
255 struct pinctrl_map **map,
256 unsigned *num_maps)
257{
258 struct samsung_pinctrl_drv_data *drvdata;
259 unsigned reserved_maps;
260 struct device_node *np;
261 int ret;
262
263 drvdata = pinctrl_dev_get_drvdata(pctldev);
264
265 reserved_maps = 0;
266 *map = NULL;
267 *num_maps = 0;
268
269 if (!of_get_child_count(np_config))
270 return samsung_dt_subnode_to_map(drvdata, pctldev->dev,
271 np_config, map,
272 &reserved_maps,
273 num_maps);
274
275 for_each_child_of_node(np_config, np) {
276 ret = samsung_dt_subnode_to_map(drvdata, pctldev->dev, np, map,
277 &reserved_maps, num_maps);
278 if (ret < 0) {
279 samsung_dt_free_map(pctldev, *map, *num_maps);
280 return ret;
281 }
282 }
283
284 return 0;
285}
286
Thomas Abraham30574f02012-09-07 06:07:19 +0900287/* list of pinctrl callbacks for the pinctrl core */
Laurent Pinchart022ab142013-02-16 10:25:07 +0100288static const struct pinctrl_ops samsung_pctrl_ops = {
Thomas Abraham30574f02012-09-07 06:07:19 +0900289 .get_groups_count = samsung_get_group_count,
290 .get_group_name = samsung_get_group_name,
291 .get_group_pins = samsung_get_group_pins,
292 .dt_node_to_map = samsung_dt_node_to_map,
293 .dt_free_map = samsung_dt_free_map,
294};
295
296/* check if the selector is a valid pin function selector */
297static int samsung_get_functions_count(struct pinctrl_dev *pctldev)
298{
299 struct samsung_pinctrl_drv_data *drvdata;
300
301 drvdata = pinctrl_dev_get_drvdata(pctldev);
302 return drvdata->nr_functions;
303}
304
305/* return the name of the pin function specified */
306static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev,
307 unsigned selector)
308{
309 struct samsung_pinctrl_drv_data *drvdata;
310
311 drvdata = pinctrl_dev_get_drvdata(pctldev);
312 return drvdata->pmx_functions[selector].name;
313}
314
315/* return the groups associated for the specified function selector */
316static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev,
317 unsigned selector, const char * const **groups,
318 unsigned * const num_groups)
319{
320 struct samsung_pinctrl_drv_data *drvdata;
321
322 drvdata = pinctrl_dev_get_drvdata(pctldev);
323 *groups = drvdata->pmx_functions[selector].groups;
324 *num_groups = drvdata->pmx_functions[selector].num_groups;
325 return 0;
326}
327
328/*
329 * given a pin number that is local to a pin controller, find out the pin bank
330 * and the register base of the pin bank.
331 */
Tomasz Figa62f14c02012-10-11 10:11:08 +0200332static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
333 unsigned pin, void __iomem **reg, u32 *offset,
Thomas Abraham30574f02012-09-07 06:07:19 +0900334 struct samsung_pin_bank **bank)
335{
Thomas Abraham30574f02012-09-07 06:07:19 +0900336 struct samsung_pin_bank *b;
337
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200338 b = drvdata->pin_banks;
Thomas Abraham30574f02012-09-07 06:07:19 +0900339
340 while ((pin >= b->pin_base) &&
341 ((b->pin_base + b->nr_pins - 1) < pin))
342 b++;
343
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +0900344 *reg = b->pctl_base + b->pctl_offset;
Thomas Abraham30574f02012-09-07 06:07:19 +0900345 *offset = pin - b->pin_base;
346 if (bank)
347 *bank = b;
Thomas Abraham30574f02012-09-07 06:07:19 +0900348}
349
350/* enable or disable a pinmux function */
351static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
Marek Szyprowski991efb02017-01-26 10:29:22 +0100352 unsigned group)
Thomas Abraham30574f02012-09-07 06:07:19 +0900353{
354 struct samsung_pinctrl_drv_data *drvdata;
Tomasz Figa94ce9442014-09-23 21:05:39 +0200355 const struct samsung_pin_bank_type *type;
Thomas Abraham30574f02012-09-07 06:07:19 +0900356 struct samsung_pin_bank *bank;
357 void __iomem *reg;
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200358 u32 mask, shift, data, pin_offset;
Tomasz Figa19846952013-03-18 22:31:50 +0100359 unsigned long flags;
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200360 const struct samsung_pmx_func *func;
361 const struct samsung_pin_group *grp;
Thomas Abraham30574f02012-09-07 06:07:19 +0900362
363 drvdata = pinctrl_dev_get_drvdata(pctldev);
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200364 func = &drvdata->pmx_functions[selector];
365 grp = &drvdata->pin_groups[group];
Thomas Abraham30574f02012-09-07 06:07:19 +0900366
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200367 pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->pin_base,
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200368 &reg, &pin_offset, &bank);
369 type = bank->type;
370 mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
371 shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC];
372 if (shift >= 32) {
373 /* Some banks have two config registers */
374 shift -= 32;
375 reg += 4;
Thomas Abraham30574f02012-09-07 06:07:19 +0900376 }
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200377
378 spin_lock_irqsave(&bank->slock, flags);
379
380 data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]);
381 data &= ~(mask << shift);
Marek Szyprowski991efb02017-01-26 10:29:22 +0100382 data |= func->val << shift;
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200383 writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]);
384
385 spin_unlock_irqrestore(&bank->slock, flags);
Thomas Abraham30574f02012-09-07 06:07:19 +0900386}
387
388/* enable a specified pinmux by writing to registers */
Linus Walleij03e9f0c2014-09-03 13:02:56 +0200389static int samsung_pinmux_set_mux(struct pinctrl_dev *pctldev,
390 unsigned selector,
391 unsigned group)
Thomas Abraham30574f02012-09-07 06:07:19 +0900392{
Marek Szyprowski991efb02017-01-26 10:29:22 +0100393 samsung_pinmux_setup(pctldev, selector, group);
Thomas Abraham30574f02012-09-07 06:07:19 +0900394 return 0;
395}
396
Thomas Abraham30574f02012-09-07 06:07:19 +0900397/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
Laurent Pinchart022ab142013-02-16 10:25:07 +0100398static const struct pinmux_ops samsung_pinmux_ops = {
Thomas Abraham30574f02012-09-07 06:07:19 +0900399 .get_functions_count = samsung_get_functions_count,
400 .get_function_name = samsung_pinmux_get_fname,
401 .get_function_groups = samsung_pinmux_get_groups,
Linus Walleij03e9f0c2014-09-03 13:02:56 +0200402 .set_mux = samsung_pinmux_set_mux,
Thomas Abraham30574f02012-09-07 06:07:19 +0900403};
404
405/* set or get the pin config settings for a specified pin */
406static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
407 unsigned long *config, bool set)
408{
409 struct samsung_pinctrl_drv_data *drvdata;
Tomasz Figa94ce9442014-09-23 21:05:39 +0200410 const struct samsung_pin_bank_type *type;
Thomas Abraham30574f02012-09-07 06:07:19 +0900411 struct samsung_pin_bank *bank;
412 void __iomem *reg_base;
413 enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
414 u32 data, width, pin_offset, mask, shift;
415 u32 cfg_value, cfg_reg;
Tomasz Figa19846952013-03-18 22:31:50 +0100416 unsigned long flags;
Thomas Abraham30574f02012-09-07 06:07:19 +0900417
418 drvdata = pinctrl_dev_get_drvdata(pctldev);
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200419 pin_to_reg_bank(drvdata, pin - drvdata->pin_base, &reg_base,
Thomas Abraham30574f02012-09-07 06:07:19 +0900420 &pin_offset, &bank);
Tomasz Figa499147c2013-03-18 22:31:52 +0100421 type = bank->type;
Thomas Abraham30574f02012-09-07 06:07:19 +0900422
Tomasz Figa499147c2013-03-18 22:31:52 +0100423 if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type])
Tomasz Figa7c367d32012-10-11 10:11:07 +0200424 return -EINVAL;
425
Tomasz Figa499147c2013-03-18 22:31:52 +0100426 width = type->fld_width[cfg_type];
Tomasz Figa43fc9e72013-03-18 22:31:53 +0100427 cfg_reg = type->reg_offset[cfg_type];
Tomasz Figa499147c2013-03-18 22:31:52 +0100428
Tomasz Figa19846952013-03-18 22:31:50 +0100429 spin_lock_irqsave(&bank->slock, flags);
430
Thomas Abraham30574f02012-09-07 06:07:19 +0900431 mask = (1 << width) - 1;
432 shift = pin_offset * width;
433 data = readl(reg_base + cfg_reg);
434
435 if (set) {
436 cfg_value = PINCFG_UNPACK_VALUE(*config);
437 data &= ~(mask << shift);
438 data |= (cfg_value << shift);
439 writel(data, reg_base + cfg_reg);
440 } else {
441 data >>= shift;
442 data &= mask;
443 *config = PINCFG_PACK(cfg_type, data);
444 }
Tomasz Figa19846952013-03-18 22:31:50 +0100445
446 spin_unlock_irqrestore(&bank->slock, flags);
447
Thomas Abraham30574f02012-09-07 06:07:19 +0900448 return 0;
449}
450
451/* set the pin config settings for a specified pin */
452static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
Sherman Yin03b054e2013-08-27 11:32:12 -0700453 unsigned long *configs, unsigned num_configs)
Thomas Abraham30574f02012-09-07 06:07:19 +0900454{
Sherman Yin03b054e2013-08-27 11:32:12 -0700455 int i, ret;
456
457 for (i = 0; i < num_configs; i++) {
458 ret = samsung_pinconf_rw(pctldev, pin, &configs[i], true);
459 if (ret < 0)
460 return ret;
461 } /* for each config */
462
463 return 0;
Thomas Abraham30574f02012-09-07 06:07:19 +0900464}
465
466/* get the pin config settings for a specified pin */
467static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
468 unsigned long *config)
469{
470 return samsung_pinconf_rw(pctldev, pin, config, false);
471}
472
473/* set the pin config settings for a specified pin group */
474static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev,
Sherman Yin03b054e2013-08-27 11:32:12 -0700475 unsigned group, unsigned long *configs,
476 unsigned num_configs)
Thomas Abraham30574f02012-09-07 06:07:19 +0900477{
478 struct samsung_pinctrl_drv_data *drvdata;
479 const unsigned int *pins;
480 unsigned int cnt;
481
482 drvdata = pinctrl_dev_get_drvdata(pctldev);
483 pins = drvdata->pin_groups[group].pins;
484
485 for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++)
Sherman Yin03b054e2013-08-27 11:32:12 -0700486 samsung_pinconf_set(pctldev, pins[cnt], configs, num_configs);
Thomas Abraham30574f02012-09-07 06:07:19 +0900487
488 return 0;
489}
490
491/* get the pin config settings for a specified pin group */
492static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev,
493 unsigned int group, unsigned long *config)
494{
495 struct samsung_pinctrl_drv_data *drvdata;
496 const unsigned int *pins;
497
498 drvdata = pinctrl_dev_get_drvdata(pctldev);
499 pins = drvdata->pin_groups[group].pins;
500 samsung_pinconf_get(pctldev, pins[0], config);
501 return 0;
502}
503
504/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
Laurent Pinchart022ab142013-02-16 10:25:07 +0100505static const struct pinconf_ops samsung_pinconf_ops = {
Thomas Abraham30574f02012-09-07 06:07:19 +0900506 .pin_config_get = samsung_pinconf_get,
507 .pin_config_set = samsung_pinconf_set,
508 .pin_config_group_get = samsung_pinconf_group_get,
509 .pin_config_group_set = samsung_pinconf_group_set,
510};
511
Youngmin Namd9ff0eb2016-02-09 00:49:28 +0900512/*
513 * The samsung_gpio_set_vlaue() should be called with "bank->slock" held
514 * to avoid race condition.
515 */
516static void samsung_gpio_set_value(struct gpio_chip *gc,
517 unsigned offset, int value)
Thomas Abraham30574f02012-09-07 06:07:19 +0900518{
Linus Walleij9f57f812015-12-08 10:18:50 +0100519 struct samsung_pin_bank *bank = gpiochip_get_data(gc);
Tomasz Figa94ce9442014-09-23 21:05:39 +0200520 const struct samsung_pin_bank_type *type = bank->type;
Thomas Abraham30574f02012-09-07 06:07:19 +0900521 void __iomem *reg;
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200522 u32 data;
Thomas Abraham30574f02012-09-07 06:07:19 +0900523
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +0900524 reg = bank->pctl_base + bank->pctl_offset;
Tomasz Figa62f14c02012-10-11 10:11:08 +0200525
Tomasz Figa43fc9e72013-03-18 22:31:53 +0100526 data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200527 data &= ~(1 << offset);
Thomas Abraham30574f02012-09-07 06:07:19 +0900528 if (value)
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200529 data |= 1 << offset;
Tomasz Figa43fc9e72013-03-18 22:31:53 +0100530 writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]);
Youngmin Namd9ff0eb2016-02-09 00:49:28 +0900531}
Tomasz Figa19846952013-03-18 22:31:50 +0100532
Youngmin Namd9ff0eb2016-02-09 00:49:28 +0900533/* gpiolib gpio_set callback function */
534static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
535{
536 struct samsung_pin_bank *bank = gpiochip_get_data(gc);
537 unsigned long flags;
538
539 spin_lock_irqsave(&bank->slock, flags);
540 samsung_gpio_set_value(gc, offset, value);
Tomasz Figa19846952013-03-18 22:31:50 +0100541 spin_unlock_irqrestore(&bank->slock, flags);
Thomas Abraham30574f02012-09-07 06:07:19 +0900542}
543
544/* gpiolib gpio_get callback function */
545static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
546{
547 void __iomem *reg;
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200548 u32 data;
Linus Walleij9f57f812015-12-08 10:18:50 +0100549 struct samsung_pin_bank *bank = gpiochip_get_data(gc);
Tomasz Figa94ce9442014-09-23 21:05:39 +0200550 const struct samsung_pin_bank_type *type = bank->type;
Thomas Abraham30574f02012-09-07 06:07:19 +0900551
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +0900552 reg = bank->pctl_base + bank->pctl_offset;
Tomasz Figa62f14c02012-10-11 10:11:08 +0200553
Tomasz Figa43fc9e72013-03-18 22:31:53 +0100554 data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200555 data >>= offset;
Thomas Abraham30574f02012-09-07 06:07:19 +0900556 data &= 1;
557 return data;
558}
559
560/*
Youngmin Namd9ff0eb2016-02-09 00:49:28 +0900561 * The samsung_gpio_set_direction() should be called with "bank->slock" held
562 * to avoid race condition.
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200563 * The calls to gpio_direction_output() and gpio_direction_input()
564 * leads to this function call.
Thomas Abraham30574f02012-09-07 06:07:19 +0900565 */
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200566static int samsung_gpio_set_direction(struct gpio_chip *gc,
567 unsigned offset, bool input)
Thomas Abraham30574f02012-09-07 06:07:19 +0900568{
Tomasz Figa94ce9442014-09-23 21:05:39 +0200569 const struct samsung_pin_bank_type *type;
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200570 struct samsung_pin_bank *bank;
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200571 void __iomem *reg;
572 u32 data, mask, shift;
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200573
Linus Walleij9f57f812015-12-08 10:18:50 +0100574 bank = gpiochip_get_data(gc);
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200575 type = bank->type;
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200576
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +0900577 reg = bank->pctl_base + bank->pctl_offset
578 + type->reg_offset[PINCFG_TYPE_FUNC];
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200579
580 mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
581 shift = offset * type->fld_width[PINCFG_TYPE_FUNC];
582 if (shift >= 32) {
583 /* Some banks have two config registers */
584 shift -= 32;
585 reg += 4;
586 }
587
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200588 data = readl(reg);
589 data &= ~(mask << shift);
590 if (!input)
Krzysztof Kozlowski4460dc22017-06-15 17:06:28 +0200591 data |= EXYNOS_PIN_FUNC_OUTPUT << shift;
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200592 writel(data, reg);
593
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200594 return 0;
Thomas Abraham30574f02012-09-07 06:07:19 +0900595}
596
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200597/* gpiolib gpio_direction_input callback function. */
598static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
599{
Youngmin Namd9ff0eb2016-02-09 00:49:28 +0900600 struct samsung_pin_bank *bank = gpiochip_get_data(gc);
601 unsigned long flags;
602 int ret;
603
604 spin_lock_irqsave(&bank->slock, flags);
605 ret = samsung_gpio_set_direction(gc, offset, true);
606 spin_unlock_irqrestore(&bank->slock, flags);
607 return ret;
Tomasz Figa18c28ca2014-07-02 17:40:59 +0200608}
609
610/* gpiolib gpio_direction_output callback function. */
Thomas Abraham30574f02012-09-07 06:07:19 +0900611static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
612 int value)
613{
Youngmin Namd9ff0eb2016-02-09 00:49:28 +0900614 struct samsung_pin_bank *bank = gpiochip_get_data(gc);
615 unsigned long flags;
616 int ret;
617
618 spin_lock_irqsave(&bank->slock, flags);
619 samsung_gpio_set_value(gc, offset, value);
620 ret = samsung_gpio_set_direction(gc, offset, false);
621 spin_unlock_irqrestore(&bank->slock, flags);
622
623 return ret;
Thomas Abraham30574f02012-09-07 06:07:19 +0900624}
625
626/*
Tomasz Figaa19fe2d2012-10-11 10:11:20 +0200627 * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
628 * and a virtual IRQ, if not already present.
629 */
630static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
631{
Linus Walleij9f57f812015-12-08 10:18:50 +0100632 struct samsung_pin_bank *bank = gpiochip_get_data(gc);
Tomasz Figaa19fe2d2012-10-11 10:11:20 +0200633 unsigned int virq;
634
635 if (!bank->irq_domain)
636 return -ENXIO;
637
638 virq = irq_create_mapping(bank->irq_domain, offset);
639
640 return (virq) ? : -ENXIO;
641}
642
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200643static struct samsung_pin_group *samsung_pinctrl_create_groups(
644 struct device *dev,
645 struct samsung_pinctrl_drv_data *drvdata,
646 unsigned int *cnt)
Thomas Abraham30574f02012-09-07 06:07:19 +0900647{
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200648 struct pinctrl_desc *ctrldesc = &drvdata->pctl;
Thomas Abraham30574f02012-09-07 06:07:19 +0900649 struct samsung_pin_group *groups, *grp;
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200650 const struct pinctrl_pin_desc *pdesc;
651 int i;
Thomas Abraham30574f02012-09-07 06:07:19 +0900652
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200653 groups = devm_kzalloc(dev, ctrldesc->npins * sizeof(*groups),
654 GFP_KERNEL);
655 if (!groups)
656 return ERR_PTR(-EINVAL);
Thomas Abraham30574f02012-09-07 06:07:19 +0900657 grp = groups;
658
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200659 pdesc = ctrldesc->pins;
660 for (i = 0; i < ctrldesc->npins; ++i, ++pdesc, ++grp) {
661 grp->name = pdesc->name;
662 grp->pins = &pdesc->number;
663 grp->num_pins = 1;
664 }
665
666 *cnt = ctrldesc->npins;
667 return groups;
668}
669
670static int samsung_pinctrl_create_function(struct device *dev,
671 struct samsung_pinctrl_drv_data *drvdata,
672 struct device_node *func_np,
673 struct samsung_pmx_func *func)
674{
675 int npins;
676 int ret;
677 int i;
678
679 if (of_property_read_u32(func_np, "samsung,pin-function", &func->val))
680 return 0;
681
682 npins = of_property_count_strings(func_np, "samsung,pins");
683 if (npins < 1) {
684 dev_err(dev, "invalid pin list in %s node", func_np->name);
685 return -EINVAL;
686 }
687
688 func->name = func_np->full_name;
689
690 func->groups = devm_kzalloc(dev, npins * sizeof(char *), GFP_KERNEL);
691 if (!func->groups)
692 return -ENOMEM;
693
694 for (i = 0; i < npins; ++i) {
695 const char *gname;
696
697 ret = of_property_read_string_index(func_np, "samsung,pins",
698 i, &gname);
699 if (ret) {
700 dev_err(dev,
701 "failed to read pin name %d from %s node\n",
702 i, func_np->name);
703 return ret;
704 }
705
706 func->groups[i] = gname;
707 }
708
709 func->num_groups = npins;
710 return 1;
711}
712
713static struct samsung_pmx_func *samsung_pinctrl_create_functions(
714 struct device *dev,
715 struct samsung_pinctrl_drv_data *drvdata,
716 unsigned int *cnt)
717{
718 struct samsung_pmx_func *functions, *func;
719 struct device_node *dev_np = dev->of_node;
720 struct device_node *cfg_np;
721 unsigned int func_cnt = 0;
722 int ret;
723
724 /*
725 * Iterate over all the child nodes of the pin controller node
726 * and create pin groups and pin function lists.
727 */
728 for_each_child_of_node(dev_np, cfg_np) {
729 struct device_node *func_np;
730
731 if (!of_get_child_count(cfg_np)) {
732 if (!of_find_property(cfg_np,
733 "samsung,pin-function", NULL))
734 continue;
735 ++func_cnt;
736 continue;
737 }
738
739 for_each_child_of_node(cfg_np, func_np) {
740 if (!of_find_property(func_np,
741 "samsung,pin-function", NULL))
742 continue;
743 ++func_cnt;
744 }
745 }
746
747 functions = devm_kzalloc(dev, func_cnt * sizeof(*functions),
748 GFP_KERNEL);
Marek Szyprowskifa5c0f42017-01-19 14:48:45 +0100749 if (!functions)
Marek Szyprowski1f7b8ea2017-01-19 14:48:46 +0100750 return ERR_PTR(-ENOMEM);
Thomas Abraham30574f02012-09-07 06:07:19 +0900751 func = functions;
752
753 /*
754 * Iterate over all the child nodes of the pin controller node
755 * and create pin groups and pin function lists.
756 */
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200757 func_cnt = 0;
Thomas Abraham30574f02012-09-07 06:07:19 +0900758 for_each_child_of_node(dev_np, cfg_np) {
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200759 struct device_node *func_np;
760
761 if (!of_get_child_count(cfg_np)) {
762 ret = samsung_pinctrl_create_function(dev, drvdata,
763 cfg_np, func);
764 if (ret < 0)
765 return ERR_PTR(ret);
766 if (ret > 0) {
767 ++func;
768 ++func_cnt;
769 }
Thomas Abraham30574f02012-09-07 06:07:19 +0900770 continue;
Thomas Abraham30574f02012-09-07 06:07:19 +0900771 }
Thomas Abraham30574f02012-09-07 06:07:19 +0900772
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200773 for_each_child_of_node(cfg_np, func_np) {
774 ret = samsung_pinctrl_create_function(dev, drvdata,
775 func_np, func);
776 if (ret < 0)
777 return ERR_PTR(ret);
778 if (ret > 0) {
779 ++func;
780 ++func_cnt;
781 }
Thomas Abraham30574f02012-09-07 06:07:19 +0900782 }
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200783 }
Thomas Abraham30574f02012-09-07 06:07:19 +0900784
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200785 *cnt = func_cnt;
786 return functions;
787}
788
789/*
790 * Parse the information about all the available pin groups and pin functions
791 * from device node of the pin-controller. A pin group is formed with all
792 * the pins listed in the "samsung,pins" property.
793 */
794
795static int samsung_pinctrl_parse_dt(struct platform_device *pdev,
796 struct samsung_pinctrl_drv_data *drvdata)
797{
798 struct device *dev = &pdev->dev;
799 struct samsung_pin_group *groups;
800 struct samsung_pmx_func *functions;
801 unsigned int grp_cnt = 0, func_cnt = 0;
802
803 groups = samsung_pinctrl_create_groups(dev, drvdata, &grp_cnt);
804 if (IS_ERR(groups)) {
805 dev_err(dev, "failed to parse pin groups\n");
806 return PTR_ERR(groups);
807 }
808
809 functions = samsung_pinctrl_create_functions(dev, drvdata, &func_cnt);
810 if (IS_ERR(functions)) {
811 dev_err(dev, "failed to parse pin functions\n");
Fabio Estevam44a074f2015-06-01 09:57:04 -0300812 return PTR_ERR(functions);
Thomas Abraham30574f02012-09-07 06:07:19 +0900813 }
814
815 drvdata->pin_groups = groups;
816 drvdata->nr_groups = grp_cnt;
817 drvdata->pmx_functions = functions;
Tomasz Figa9a2c1c32014-07-02 17:41:03 +0200818 drvdata->nr_functions = func_cnt;
Thomas Abraham30574f02012-09-07 06:07:19 +0900819
820 return 0;
821}
822
823/* register the pinctrl interface with the pinctrl subsystem */
Greg Kroah-Hartman150632b2012-12-21 13:10:23 -0800824static int samsung_pinctrl_register(struct platform_device *pdev,
825 struct samsung_pinctrl_drv_data *drvdata)
Thomas Abraham30574f02012-09-07 06:07:19 +0900826{
827 struct pinctrl_desc *ctrldesc = &drvdata->pctl;
828 struct pinctrl_pin_desc *pindesc, *pdesc;
829 struct samsung_pin_bank *pin_bank;
830 char *pin_names;
831 int pin, bank, ret;
832
833 ctrldesc->name = "samsung-pinctrl";
834 ctrldesc->owner = THIS_MODULE;
835 ctrldesc->pctlops = &samsung_pctrl_ops;
836 ctrldesc->pmxops = &samsung_pinmux_ops;
837 ctrldesc->confops = &samsung_pinconf_ops;
838
839 pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200840 drvdata->nr_pins, GFP_KERNEL);
Marek Szyprowskifa5c0f42017-01-19 14:48:45 +0100841 if (!pindesc)
Thomas Abraham30574f02012-09-07 06:07:19 +0900842 return -ENOMEM;
Thomas Abraham30574f02012-09-07 06:07:19 +0900843 ctrldesc->pins = pindesc;
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200844 ctrldesc->npins = drvdata->nr_pins;
Thomas Abraham30574f02012-09-07 06:07:19 +0900845
846 /* dynamically populate the pin number and pin name for pindesc */
847 for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200848 pdesc->number = pin + drvdata->pin_base;
Thomas Abraham30574f02012-09-07 06:07:19 +0900849
850 /*
851 * allocate space for storing the dynamically generated names for all
852 * the pins which belong to this pin-controller.
853 */
854 pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH *
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200855 drvdata->nr_pins, GFP_KERNEL);
Marek Szyprowskifa5c0f42017-01-19 14:48:45 +0100856 if (!pin_names)
Thomas Abraham30574f02012-09-07 06:07:19 +0900857 return -ENOMEM;
Thomas Abraham30574f02012-09-07 06:07:19 +0900858
859 /* for each pin, the name of the pin is pin-bank name + pin number */
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200860 for (bank = 0; bank < drvdata->nr_banks; bank++) {
861 pin_bank = &drvdata->pin_banks[bank];
Thomas Abraham30574f02012-09-07 06:07:19 +0900862 for (pin = 0; pin < pin_bank->nr_pins; pin++) {
863 sprintf(pin_names, "%s-%d", pin_bank->name, pin);
864 pdesc = pindesc + pin_bank->pin_base + pin;
865 pdesc->name = pin_names;
866 pin_names += PIN_NAME_LENGTH;
867 }
868 }
869
Tomasz Figa529301c2013-08-20 18:16:21 +0200870 ret = samsung_pinctrl_parse_dt(pdev, drvdata);
871 if (ret)
872 return ret;
873
Laxman Dewangan9ed19e02016-02-28 14:36:42 +0530874 drvdata->pctl_dev = devm_pinctrl_register(&pdev->dev, ctrldesc,
875 drvdata);
Masahiro Yamada323de9e2015-06-09 13:01:16 +0900876 if (IS_ERR(drvdata->pctl_dev)) {
Thomas Abraham30574f02012-09-07 06:07:19 +0900877 dev_err(&pdev->dev, "could not register pinctrl driver\n");
Masahiro Yamada323de9e2015-06-09 13:01:16 +0900878 return PTR_ERR(drvdata->pctl_dev);
Thomas Abraham30574f02012-09-07 06:07:19 +0900879 }
880
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200881 for (bank = 0; bank < drvdata->nr_banks; ++bank) {
882 pin_bank = &drvdata->pin_banks[bank];
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200883 pin_bank->grange.name = pin_bank->name;
884 pin_bank->grange.id = bank;
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200885 pin_bank->grange.pin_base = drvdata->pin_base
Tomasz Figa6c6ce622014-07-02 17:41:00 +0200886 + pin_bank->pin_base;
Charles Keepax1abd18d2017-03-22 17:15:34 +0000887 pin_bank->grange.base = pin_bank->grange.pin_base;
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200888 pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
889 pin_bank->grange.gc = &pin_bank->gpio_chip;
890 pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange);
891 }
Thomas Abraham30574f02012-09-07 06:07:19 +0900892
Thomas Abraham30574f02012-09-07 06:07:19 +0900893 return 0;
894}
895
Charles Keepax1abd18d2017-03-22 17:15:34 +0000896/* unregister the pinctrl interface with the pinctrl subsystem */
897static int samsung_pinctrl_unregister(struct platform_device *pdev,
898 struct samsung_pinctrl_drv_data *drvdata)
899{
900 struct samsung_pin_bank *bank = drvdata->pin_banks;
901 int i;
902
903 for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
904 pinctrl_remove_gpio_range(drvdata->pctl_dev, &bank->grange);
905
906 return 0;
907}
908
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200909static const struct gpio_chip samsung_gpiolib_chip = {
Jonas Gorski98c85d52015-10-11 17:34:19 +0200910 .request = gpiochip_generic_request,
911 .free = gpiochip_generic_free,
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200912 .set = samsung_gpio_set,
913 .get = samsung_gpio_get,
914 .direction_input = samsung_gpio_direction_input,
915 .direction_output = samsung_gpio_direction_output,
Tomasz Figaa19fe2d2012-10-11 10:11:20 +0200916 .to_irq = samsung_gpio_to_irq,
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200917 .owner = THIS_MODULE,
918};
919
Thomas Abraham30574f02012-09-07 06:07:19 +0900920/* register the gpiolib interface with the gpiolib subsystem */
Greg Kroah-Hartman150632b2012-12-21 13:10:23 -0800921static int samsung_gpiolib_register(struct platform_device *pdev,
922 struct samsung_pinctrl_drv_data *drvdata)
Thomas Abraham30574f02012-09-07 06:07:19 +0900923{
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200924 struct samsung_pin_bank *bank = drvdata->pin_banks;
Thomas Abraham30574f02012-09-07 06:07:19 +0900925 struct gpio_chip *gc;
926 int ret;
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200927 int i;
Thomas Abraham30574f02012-09-07 06:07:19 +0900928
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200929 for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200930 bank->gpio_chip = samsung_gpiolib_chip;
Thomas Abraham30574f02012-09-07 06:07:19 +0900931
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200932 gc = &bank->gpio_chip;
Charles Keepax1abd18d2017-03-22 17:15:34 +0000933 gc->base = bank->grange.base;
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200934 gc->ngpio = bank->nr_pins;
Linus Walleij58383c782015-11-04 09:56:26 +0100935 gc->parent = &pdev->dev;
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200936 gc->of_node = bank->of_node;
937 gc->label = bank->name;
938
Charles Keepaxf69ae4f2017-03-22 17:15:35 +0000939 ret = devm_gpiochip_add_data(&pdev->dev, gc, bank);
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200940 if (ret) {
941 dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
942 gc->label, ret);
Charles Keepaxf69ae4f2017-03-22 17:15:35 +0000943 return ret;
Tomasz Figad3a7b9e2012-10-11 10:11:17 +0200944 }
Thomas Abraham30574f02012-09-07 06:07:19 +0900945 }
946
947 return 0;
Thomas Abraham30574f02012-09-07 06:07:19 +0900948}
949
Thomas Abraham30574f02012-09-07 06:07:19 +0900950/* retrieve the soc specific data */
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200951static const struct samsung_pin_ctrl *
952samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
953 struct platform_device *pdev)
Thomas Abraham30574f02012-09-07 06:07:19 +0900954{
955 int id;
Tomasz Figa6defe9a2012-10-11 10:11:14 +0200956 struct device_node *node = pdev->dev.of_node;
Tomasz Figaab663782012-10-11 10:11:13 +0200957 struct device_node *np;
Tomasz Figa8100cf42014-09-23 21:05:41 +0200958 const struct samsung_pin_bank_data *bdata;
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200959 const struct samsung_pin_ctrl *ctrl;
Tomasz Figa40ba6222012-10-11 10:11:09 +0200960 struct samsung_pin_bank *bank;
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +0900961 struct resource *res;
962 void __iomem *virt_base[SAMSUNG_PINCTRL_NUM_RESOURCES];
Tomasz Figa40ba6222012-10-11 10:11:09 +0200963 int i;
Thomas Abraham30574f02012-09-07 06:07:19 +0900964
Tomasz Figa6defe9a2012-10-11 10:11:14 +0200965 id = of_alias_get_id(node, "pinctrl");
Thomas Abraham30574f02012-09-07 06:07:19 +0900966 if (id < 0) {
967 dev_err(&pdev->dev, "failed to get alias id\n");
Tomasz Figa87993272014-09-23 21:05:37 +0200968 return ERR_PTR(-ENOENT);
Thomas Abraham30574f02012-09-07 06:07:19 +0900969 }
Marek Szyprowski9abc2b92017-01-26 10:29:23 +0100970 ctrl = of_device_get_match_data(&pdev->dev);
971 ctrl += id;
Tomasz Figa40ba6222012-10-11 10:11:09 +0200972
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200973 d->suspend = ctrl->suspend;
974 d->resume = ctrl->resume;
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200975 d->nr_banks = ctrl->nr_banks;
Tomasz Figa8100cf42014-09-23 21:05:41 +0200976 d->pin_banks = devm_kcalloc(&pdev->dev, d->nr_banks,
977 sizeof(*d->pin_banks), GFP_KERNEL);
978 if (!d->pin_banks)
979 return ERR_PTR(-ENOMEM);
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200980
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +0900981 if (ctrl->nr_ext_resources + 1 > SAMSUNG_PINCTRL_NUM_RESOURCES)
982 return ERR_PTR(-EINVAL);
983
984 for (i = 0; i < ctrl->nr_ext_resources + 1; i++) {
985 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
Andrzej Hajda59f34e82017-02-23 11:12:40 +0100986 if (!res) {
987 dev_err(&pdev->dev, "failed to get mem%d resource\n", i);
988 return ERR_PTR(-EINVAL);
989 }
990 virt_base[i] = devm_ioremap(&pdev->dev, res->start,
991 resource_size(res));
992 if (!virt_base[i]) {
993 dev_err(&pdev->dev, "failed to ioremap %pR\n", res);
994 return ERR_PTR(-EIO);
995 }
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +0900996 }
997
Tomasz Figa1bf00d72014-09-23 21:05:40 +0200998 bank = d->pin_banks;
Tomasz Figa8100cf42014-09-23 21:05:41 +0200999 bdata = ctrl->pin_banks;
1000 for (i = 0; i < ctrl->nr_banks; ++i, ++bdata, ++bank) {
1001 bank->type = bdata->type;
1002 bank->pctl_offset = bdata->pctl_offset;
1003 bank->nr_pins = bdata->nr_pins;
1004 bank->eint_func = bdata->eint_func;
1005 bank->eint_type = bdata->eint_type;
1006 bank->eint_mask = bdata->eint_mask;
1007 bank->eint_offset = bdata->eint_offset;
1008 bank->name = bdata->name;
1009
Tomasz Figa19846952013-03-18 22:31:50 +01001010 spin_lock_init(&bank->slock);
Tomasz Figa6defe9a2012-10-11 10:11:14 +02001011 bank->drvdata = d;
Tomasz Figa1bf00d72014-09-23 21:05:40 +02001012 bank->pin_base = d->nr_pins;
1013 d->nr_pins += bank->nr_pins;
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +09001014
1015 bank->eint_base = virt_base[0];
1016 bank->pctl_base = virt_base[bdata->pctl_res_idx];
Tomasz Figa40ba6222012-10-11 10:11:09 +02001017 }
Krzysztof Kozlowskicee74132017-06-15 17:46:37 +02001018 /*
1019 * Legacy platforms should provide only one resource with IO memory.
1020 * Store it as virt_base because legacy driver needs to access it
1021 * through samsung_pinctrl_drv_data.
1022 */
1023 d->virt_base = virt_base[0];
Tomasz Figa40ba6222012-10-11 10:11:09 +02001024
Tomasz Figaab663782012-10-11 10:11:13 +02001025 for_each_child_of_node(node, np) {
1026 if (!of_find_property(np, "gpio-controller", NULL))
1027 continue;
Tomasz Figa1bf00d72014-09-23 21:05:40 +02001028 bank = d->pin_banks;
1029 for (i = 0; i < d->nr_banks; ++i, ++bank) {
Tomasz Figaab663782012-10-11 10:11:13 +02001030 if (!strcmp(bank->name, np->name)) {
1031 bank->of_node = np;
1032 break;
1033 }
1034 }
1035 }
1036
Tomasz Figa1bf00d72014-09-23 21:05:40 +02001037 d->pin_base = pin_base;
1038 pin_base += d->nr_pins;
Tomasz Figa40ba6222012-10-11 10:11:09 +02001039
1040 return ctrl;
Thomas Abraham30574f02012-09-07 06:07:19 +09001041}
1042
Greg Kroah-Hartman150632b2012-12-21 13:10:23 -08001043static int samsung_pinctrl_probe(struct platform_device *pdev)
Thomas Abraham30574f02012-09-07 06:07:19 +09001044{
1045 struct samsung_pinctrl_drv_data *drvdata;
Tomasz Figa1bf00d72014-09-23 21:05:40 +02001046 const struct samsung_pin_ctrl *ctrl;
Thomas Abraham30574f02012-09-07 06:07:19 +09001047 struct device *dev = &pdev->dev;
Thomas Abraham30574f02012-09-07 06:07:19 +09001048 struct resource *res;
1049 int ret;
1050
Thomas Abraham30574f02012-09-07 06:07:19 +09001051 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
Sylwester Nawrockib09eed72016-09-01 13:59:00 +02001052 if (!drvdata)
Thomas Abraham30574f02012-09-07 06:07:19 +09001053 return -ENOMEM;
Tomasz Figa6defe9a2012-10-11 10:11:14 +02001054
1055 ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
Tomasz Figa87993272014-09-23 21:05:37 +02001056 if (IS_ERR(ctrl)) {
Tomasz Figa6defe9a2012-10-11 10:11:14 +02001057 dev_err(&pdev->dev, "driver data not available\n");
Tomasz Figa87993272014-09-23 21:05:37 +02001058 return PTR_ERR(ctrl);
Tomasz Figa6defe9a2012-10-11 10:11:14 +02001059 }
Thomas Abraham30574f02012-09-07 06:07:19 +09001060 drvdata->dev = dev;
1061
Thomas Abraham30574f02012-09-07 06:07:19 +09001062 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1063 if (res)
1064 drvdata->irq = res->start;
1065
Marek Szyprowski1fc8ad82017-01-26 10:29:24 +01001066 if (ctrl->retention_data) {
1067 drvdata->retention_ctrl = ctrl->retention_data->init(drvdata,
1068 ctrl->retention_data);
1069 if (IS_ERR(drvdata->retention_ctrl))
1070 return PTR_ERR(drvdata->retention_ctrl);
1071 }
1072
Charles Keepax1abd18d2017-03-22 17:15:34 +00001073 ret = samsung_pinctrl_register(pdev, drvdata);
Thomas Abraham30574f02012-09-07 06:07:19 +09001074 if (ret)
1075 return ret;
1076
Charles Keepax1abd18d2017-03-22 17:15:34 +00001077 ret = samsung_gpiolib_register(pdev, drvdata);
Thomas Abraham30574f02012-09-07 06:07:19 +09001078 if (ret) {
Charles Keepax1abd18d2017-03-22 17:15:34 +00001079 samsung_pinctrl_unregister(pdev, drvdata);
Thomas Abraham30574f02012-09-07 06:07:19 +09001080 return ret;
1081 }
1082
1083 if (ctrl->eint_gpio_init)
1084 ctrl->eint_gpio_init(drvdata);
1085 if (ctrl->eint_wkup_init)
1086 ctrl->eint_wkup_init(drvdata);
1087
1088 platform_set_drvdata(pdev, drvdata);
Doug Andersond9f99862013-05-16 21:33:18 -07001089
Thomas Abraham30574f02012-09-07 06:07:19 +09001090 return 0;
1091}
1092
Doug Andersond9f99862013-05-16 21:33:18 -07001093/**
Marek Szyprowski2b24efa2017-01-26 10:29:27 +01001094 * samsung_pinctrl_suspend - save pinctrl state for suspend
Doug Andersond9f99862013-05-16 21:33:18 -07001095 *
1096 * Save data for all banks handled by this device.
1097 */
Arnd Bergmann304c92e2017-02-01 17:16:24 +01001098static int __maybe_unused samsung_pinctrl_suspend(struct device *dev)
Doug Andersond9f99862013-05-16 21:33:18 -07001099{
Marek Szyprowski2b24efa2017-01-26 10:29:27 +01001100 struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev);
Doug Andersond9f99862013-05-16 21:33:18 -07001101 int i;
1102
Tomasz Figa1bf00d72014-09-23 21:05:40 +02001103 for (i = 0; i < drvdata->nr_banks; i++) {
1104 struct samsung_pin_bank *bank = &drvdata->pin_banks[i];
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +09001105 void __iomem *reg = bank->pctl_base + bank->pctl_offset;
Tomasz Figa94ce9442014-09-23 21:05:39 +02001106 const u8 *offs = bank->type->reg_offset;
1107 const u8 *widths = bank->type->fld_width;
Doug Andersond9f99862013-05-16 21:33:18 -07001108 enum pincfg_type type;
1109
1110 /* Registers without a powerdown config aren't lost */
1111 if (!widths[PINCFG_TYPE_CON_PDN])
1112 continue;
1113
1114 for (type = 0; type < PINCFG_TYPE_NUM; type++)
1115 if (widths[type])
1116 bank->pm_save[type] = readl(reg + offs[type]);
1117
1118 if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
1119 /* Some banks have two config registers */
1120 bank->pm_save[PINCFG_TYPE_NUM] =
1121 readl(reg + offs[PINCFG_TYPE_FUNC] + 4);
1122 pr_debug("Save %s @ %p (con %#010x %08x)\n",
1123 bank->name, reg,
1124 bank->pm_save[PINCFG_TYPE_FUNC],
1125 bank->pm_save[PINCFG_TYPE_NUM]);
1126 } else {
1127 pr_debug("Save %s @ %p (con %#010x)\n", bank->name,
1128 reg, bank->pm_save[PINCFG_TYPE_FUNC]);
1129 }
1130 }
Tomasz Figa21c21992013-05-17 18:24:30 +02001131
Tomasz Figa1bf00d72014-09-23 21:05:40 +02001132 if (drvdata->suspend)
1133 drvdata->suspend(drvdata);
Marek Szyprowski1fc8ad82017-01-26 10:29:24 +01001134 if (drvdata->retention_ctrl && drvdata->retention_ctrl->enable)
1135 drvdata->retention_ctrl->enable(drvdata);
Marek Szyprowski2b24efa2017-01-26 10:29:27 +01001136
1137 return 0;
Doug Andersond9f99862013-05-16 21:33:18 -07001138}
1139
1140/**
Marek Szyprowski2b24efa2017-01-26 10:29:27 +01001141 * samsung_pinctrl_resume - restore pinctrl state from suspend
Doug Andersond9f99862013-05-16 21:33:18 -07001142 *
1143 * Restore one of the banks that was saved during suspend.
1144 *
1145 * We don't bother doing anything complicated to avoid glitching lines since
1146 * we're called before pad retention is turned off.
1147 */
Arnd Bergmann304c92e2017-02-01 17:16:24 +01001148static int __maybe_unused samsung_pinctrl_resume(struct device *dev)
Doug Andersond9f99862013-05-16 21:33:18 -07001149{
Marek Szyprowski2b24efa2017-01-26 10:29:27 +01001150 struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev);
Doug Andersond9f99862013-05-16 21:33:18 -07001151 int i;
1152
Tomasz Figa1bf00d72014-09-23 21:05:40 +02001153 if (drvdata->resume)
1154 drvdata->resume(drvdata);
Tomasz Figa21c21992013-05-17 18:24:30 +02001155
Tomasz Figa1bf00d72014-09-23 21:05:40 +02001156 for (i = 0; i < drvdata->nr_banks; i++) {
1157 struct samsung_pin_bank *bank = &drvdata->pin_banks[i];
Chanwoo Choi8b1bd11c2016-11-09 17:40:10 +09001158 void __iomem *reg = bank->pctl_base + bank->pctl_offset;
Tomasz Figa94ce9442014-09-23 21:05:39 +02001159 const u8 *offs = bank->type->reg_offset;
1160 const u8 *widths = bank->type->fld_width;
Doug Andersond9f99862013-05-16 21:33:18 -07001161 enum pincfg_type type;
1162
1163 /* Registers without a powerdown config aren't lost */
1164 if (!widths[PINCFG_TYPE_CON_PDN])
1165 continue;
1166
1167 if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
1168 /* Some banks have two config registers */
1169 pr_debug("%s @ %p (con %#010x %08x => %#010x %08x)\n",
1170 bank->name, reg,
1171 readl(reg + offs[PINCFG_TYPE_FUNC]),
1172 readl(reg + offs[PINCFG_TYPE_FUNC] + 4),
1173 bank->pm_save[PINCFG_TYPE_FUNC],
1174 bank->pm_save[PINCFG_TYPE_NUM]);
1175 writel(bank->pm_save[PINCFG_TYPE_NUM],
1176 reg + offs[PINCFG_TYPE_FUNC] + 4);
1177 } else {
1178 pr_debug("%s @ %p (con %#010x => %#010x)\n", bank->name,
1179 reg, readl(reg + offs[PINCFG_TYPE_FUNC]),
1180 bank->pm_save[PINCFG_TYPE_FUNC]);
1181 }
1182 for (type = 0; type < PINCFG_TYPE_NUM; type++)
1183 if (widths[type])
1184 writel(bank->pm_save[type], reg + offs[type]);
1185 }
Marek Szyprowski1fc8ad82017-01-26 10:29:24 +01001186
1187 if (drvdata->retention_ctrl && drvdata->retention_ctrl->disable)
1188 drvdata->retention_ctrl->disable(drvdata);
Doug Andersond9f99862013-05-16 21:33:18 -07001189
1190 return 0;
1191}
Doug Andersond9f99862013-05-16 21:33:18 -07001192
Thomas Abraham30574f02012-09-07 06:07:19 +09001193static const struct of_device_id samsung_pinctrl_dt_match[] = {
Krzysztof Kozlowskicfa76dd2017-05-16 20:56:27 +02001194#ifdef CONFIG_PINCTRL_EXYNOS_ARM
Tomasz Figad97f5b92014-04-14 10:45:47 +09001195 { .compatible = "samsung,exynos3250-pinctrl",
Masahiro Yamada7ddaa432017-04-26 06:34:23 +09001196 .data = exynos3250_pin_ctrl },
Kukjin Kimb533c862013-01-02 16:05:42 -08001197 { .compatible = "samsung,exynos4210-pinctrl",
Masahiro Yamada7ddaa432017-04-26 06:34:23 +09001198 .data = exynos4210_pin_ctrl },
Kukjin Kimb533c862013-01-02 16:05:42 -08001199 { .compatible = "samsung,exynos4x12-pinctrl",
Masahiro Yamada7ddaa432017-04-26 06:34:23 +09001200 .data = exynos4x12_pin_ctrl },
Thomas Abrahamf67faf42012-12-28 10:37:27 -08001201 { .compatible = "samsung,exynos5250-pinctrl",
Masahiro Yamada7ddaa432017-04-26 06:34:23 +09001202 .data = exynos5250_pin_ctrl },
Young-Gun Jang9a8b6072014-02-05 11:51:28 +05301203 { .compatible = "samsung,exynos5260-pinctrl",
Masahiro Yamada7ddaa432017-04-26 06:34:23 +09001204 .data = exynos5260_pin_ctrl },
Hakjoo Kim023e06d2015-03-15 23:00:32 +01001205 { .compatible = "samsung,exynos5410-pinctrl",
Masahiro Yamada7ddaa432017-04-26 06:34:23 +09001206 .data = exynos5410_pin_ctrl },
Leela Krishna Amudala983dbeb2013-06-19 22:16:26 +09001207 { .compatible = "samsung,exynos5420-pinctrl",
Masahiro Yamada7ddaa432017-04-26 06:34:23 +09001208 .data = exynos5420_pin_ctrl },
Mateusz Krawczuk608a26a2013-08-27 15:08:10 +02001209 { .compatible = "samsung,s5pv210-pinctrl",
Masahiro Yamada7ddaa432017-04-26 06:34:23 +09001210 .data = s5pv210_pin_ctrl },
Krzysztof Kozlowskicfa76dd2017-05-16 20:56:27 +02001211#endif
1212#ifdef CONFIG_PINCTRL_EXYNOS_ARM64
1213 { .compatible = "samsung,exynos5433-pinctrl",
1214 .data = exynos5433_pin_ctrl },
Naveen Krishna Ch50cea0c2014-10-09 19:24:32 +05301215 { .compatible = "samsung,exynos7-pinctrl",
Masahiro Yamada7ddaa432017-04-26 06:34:23 +09001216 .data = exynos7_pin_ctrl },
Tomasz Figad5517be2013-03-18 22:31:51 +01001217#endif
Tomasz Figa61dd7262013-03-18 22:31:55 +01001218#ifdef CONFIG_PINCTRL_S3C64XX
1219 { .compatible = "samsung,s3c64xx-pinctrl",
1220 .data = s3c64xx_pin_ctrl },
1221#endif
Heiko Stuebneraf99a752013-05-21 00:56:13 +09001222#ifdef CONFIG_PINCTRL_S3C24XX
1223 { .compatible = "samsung,s3c2412-pinctrl",
1224 .data = s3c2412_pin_ctrl },
1225 { .compatible = "samsung,s3c2416-pinctrl",
1226 .data = s3c2416_pin_ctrl },
1227 { .compatible = "samsung,s3c2440-pinctrl",
1228 .data = s3c2440_pin_ctrl },
1229 { .compatible = "samsung,s3c2450-pinctrl",
1230 .data = s3c2450_pin_ctrl },
1231#endif
Thomas Abraham30574f02012-09-07 06:07:19 +09001232 {},
1233};
Thomas Abraham30574f02012-09-07 06:07:19 +09001234
Marek Szyprowski2b24efa2017-01-26 10:29:27 +01001235static const struct dev_pm_ops samsung_pinctrl_pm_ops = {
1236 SET_LATE_SYSTEM_SLEEP_PM_OPS(samsung_pinctrl_suspend,
1237 samsung_pinctrl_resume)
1238};
1239
Thomas Abraham30574f02012-09-07 06:07:19 +09001240static struct platform_driver samsung_pinctrl_driver = {
1241 .probe = samsung_pinctrl_probe,
1242 .driver = {
1243 .name = "samsung-pinctrl",
Sachin Kamat606fca92013-09-28 17:38:48 +05301244 .of_match_table = samsung_pinctrl_dt_match,
Krzysztof Kozlowskia0ee2ac2016-05-17 08:02:06 +02001245 .suppress_bind_attrs = true,
Marek Szyprowski2b24efa2017-01-26 10:29:27 +01001246 .pm = &samsung_pinctrl_pm_ops,
Thomas Abraham30574f02012-09-07 06:07:19 +09001247 },
1248};
1249
1250static int __init samsung_pinctrl_drv_register(void)
1251{
Thomas Abraham30574f02012-09-07 06:07:19 +09001252 return platform_driver_register(&samsung_pinctrl_driver);
1253}
1254postcore_initcall(samsung_pinctrl_drv_register);