Blame view

drivers/pinctrl/sh-pfc/gpio.c 9.31 KB
b3c185a76   Paul Mundt   sh: pfc: Split ou...
1
2
3
4
5
6
7
8
9
10
  /*
   * SuperH Pin Function Controller GPIO driver.
   *
   * Copyright (C) 2008 Magnus Damm
   * Copyright (C) 2009 - 2012 Paul Mundt
   *
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file "COPYING" in the main directory of this archive
   * for more details.
   */
c6193eacd   Laurent Pinchart   sh-pfc: Move plat...
11

1724acfd5   Laurent Pinchart   sh-pfc: Use devm_...
12
  #include <linux/device.h>
b3c185a76   Paul Mundt   sh: pfc: Split ou...
13
  #include <linux/gpio.h>
90efde223   Laurent Pinchart   sh-pfc: Sort head...
14
  #include <linux/init.h>
b3c185a76   Paul Mundt   sh: pfc: Split ou...
15
  #include <linux/module.h>
ca5481c68   Paul Mundt   sh: pfc: Rudiment...
16
  #include <linux/pinctrl/consumer.h>
90efde223   Laurent Pinchart   sh-pfc: Sort head...
17
18
  #include <linux/slab.h>
  #include <linux/spinlock.h>
b3c185a76   Paul Mundt   sh: pfc: Split ou...
19

f9165132c   Laurent Pinchart   sh-pfc: Move priv...
20
  #include "core.h"
51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
21
22
  struct sh_pfc_gpio_data_reg {
  	const struct pinmux_data_reg *info;
fc88936ad   Geert Uytterhoeven   pinctrl: sh-pfc: ...
23
  	u32 shadow;
51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
24
  };
1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
25
26
27
28
  struct sh_pfc_gpio_pin {
  	u8 dbit;
  	u8 dreg;
  };
b3c185a76   Paul Mundt   sh: pfc: Split ou...
29
  struct sh_pfc_chip {
1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
30
31
  	struct sh_pfc			*pfc;
  	struct gpio_chip		gpio_chip;
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
32

1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
33
  	struct sh_pfc_window		*mem;
51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
34
  	struct sh_pfc_gpio_data_reg	*regs;
1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
35
  	struct sh_pfc_gpio_pin		*pins;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
36
  };
b3c185a76   Paul Mundt   sh: pfc: Split ou...
37
38
  static struct sh_pfc *gpio_to_pfc(struct gpio_chip *gc)
  {
7cb093c4b   Linus Walleij   pinctrl: sh-pfc: ...
39
40
  	struct sh_pfc_chip *chip = gpiochip_get_data(gc);
  	return chip->pfc;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
41
  }
757b055a6   Laurent Pinchart   sh-pfc: Rename gp...
42
  static void gpio_get_data_reg(struct sh_pfc_chip *chip, unsigned int offset,
51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
43
44
  			      struct sh_pfc_gpio_data_reg **reg,
  			      unsigned int *bit)
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
45
  {
757b055a6   Laurent Pinchart   sh-pfc: Rename gp...
46
  	int idx = sh_pfc_get_pin_index(chip->pfc, offset);
1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
47
  	struct sh_pfc_gpio_pin *gpio_pin = &chip->pins[idx];
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
48

1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
49
50
  	*reg = &chip->regs[gpio_pin->dreg];
  	*bit = gpio_pin->dbit;
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
51
  }
fc88936ad   Geert Uytterhoeven   pinctrl: sh-pfc: ...
52
53
  static u32 gpio_read_data_reg(struct sh_pfc_chip *chip,
  			      const struct pinmux_data_reg *dreg)
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
54
  {
1f34de05e   Geert Uytterhoeven   pinctrl: sh-pfc: ...
55
56
  	phys_addr_t address = dreg->reg;
  	void __iomem *mem = address - chip->mem->phys + chip->mem->virt;
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
57
58
59
  
  	return sh_pfc_read_raw_reg(mem, dreg->reg_width);
  }
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
60

e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
61
  static void gpio_write_data_reg(struct sh_pfc_chip *chip,
fc88936ad   Geert Uytterhoeven   pinctrl: sh-pfc: ...
62
  				const struct pinmux_data_reg *dreg, u32 value)
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
63
  {
1f34de05e   Geert Uytterhoeven   pinctrl: sh-pfc: ...
64
65
  	phys_addr_t address = dreg->reg;
  	void __iomem *mem = address - chip->mem->phys + chip->mem->virt;
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
66

e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
67
68
  	sh_pfc_write_raw_reg(mem, dreg->reg_width, value);
  }
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
69

757b055a6   Laurent Pinchart   sh-pfc: Rename gp...
70
  static void gpio_setup_data_reg(struct sh_pfc_chip *chip, unsigned idx)
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
71
  {
1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
72
  	struct sh_pfc *pfc = chip->pfc;
757b055a6   Laurent Pinchart   sh-pfc: Rename gp...
73
74
  	struct sh_pfc_gpio_pin *gpio_pin = &chip->pins[idx];
  	const struct sh_pfc_pin *pin = &pfc->info->pins[idx];
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
75
76
77
  	const struct pinmux_data_reg *dreg;
  	unsigned int bit;
  	unsigned int i;
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
78

17c7cbb0e   Geert Uytterhoeven   pinctrl: sh-pfc: ...
79
  	for (i = 0, dreg = pfc->info->data_regs; dreg->reg_width; ++i, ++dreg) {
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
80
  		for (bit = 0; bit < dreg->reg_width; bit++) {
1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
81
82
83
  			if (dreg->enum_ids[bit] == pin->enum_id) {
  				gpio_pin->dreg = i;
  				gpio_pin->dbit = bit;
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
84
85
86
  				return;
  			}
  		}
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
87
88
89
90
  	}
  
  	BUG();
  }
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
91
  static int gpio_setup_data_regs(struct sh_pfc_chip *chip)
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
92
  {
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
93
  	struct sh_pfc *pfc = chip->pfc;
51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
94
  	const struct pinmux_data_reg *dreg;
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
95
  	unsigned int i;
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
96

51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  	/* Count the number of data registers, allocate memory and initialize
  	 * them.
  	 */
  	for (i = 0; pfc->info->data_regs[i].reg_width; ++i)
  		;
  
  	chip->regs = devm_kzalloc(pfc->dev, i * sizeof(*chip->regs),
  				  GFP_KERNEL);
  	if (chip->regs == NULL)
  		return -ENOMEM;
  
  	for (i = 0, dreg = pfc->info->data_regs; dreg->reg_width; ++i, ++dreg) {
  		chip->regs[i].info = dreg;
  		chip->regs[i].shadow = gpio_read_data_reg(chip, dreg);
  	}
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
112

e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
113
114
115
  	for (i = 0; i < pfc->info->nr_pins; i++) {
  		if (pfc->info->pins[i].enum_id == 0)
  			continue;
1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
116
  		gpio_setup_data_reg(chip, i);
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
117
  	}
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
118
119
  
  	return 0;
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
120
  }
16883814e   Laurent Pinchart   sh-pfc: Split pin...
121
122
123
  /* -----------------------------------------------------------------------------
   * Pin GPIOs
   */
b3c185a76   Paul Mundt   sh: pfc: Split ou...
124

16883814e   Laurent Pinchart   sh-pfc: Split pin...
125
  static int gpio_pin_request(struct gpio_chip *gc, unsigned offset)
b3c185a76   Paul Mundt   sh: pfc: Split ou...
126
  {
0b73ee5d5   Laurent Pinchart   sh-pfc: Simplify ...
127
  	struct sh_pfc *pfc = gpio_to_pfc(gc);
1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
128
  	int idx = sh_pfc_get_pin_index(pfc, offset);
0b73ee5d5   Laurent Pinchart   sh-pfc: Simplify ...
129

1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
130
  	if (idx < 0 || pfc->info->pins[idx].enum_id == 0)
0b73ee5d5   Laurent Pinchart   sh-pfc: Simplify ...
131
  		return -EINVAL;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
132
  	return pinctrl_request_gpio(offset);
b3c185a76   Paul Mundt   sh: pfc: Split ou...
133
  }
16883814e   Laurent Pinchart   sh-pfc: Split pin...
134
  static void gpio_pin_free(struct gpio_chip *gc, unsigned offset)
b3c185a76   Paul Mundt   sh: pfc: Split ou...
135
  {
16883814e   Laurent Pinchart   sh-pfc: Split pin...
136
  	return pinctrl_free_gpio(offset);
b3c185a76   Paul Mundt   sh: pfc: Split ou...
137
  }
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
138
139
  static void gpio_pin_set_value(struct sh_pfc_chip *chip, unsigned offset,
  			       int value)
b3c185a76   Paul Mundt   sh: pfc: Split ou...
140
  {
51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
141
  	struct sh_pfc_gpio_data_reg *reg;
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
142
  	unsigned int bit;
cef28a289   Geert Uytterhoeven   pinctrl: sh-pfc: ...
143
  	unsigned int pos;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
144

51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
145
  	gpio_get_data_reg(chip, offset, &reg, &bit);
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
146

51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
147
  	pos = reg->info->reg_width - (bit + 1);
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
148
149
  
  	if (value)
fc88936ad   Geert Uytterhoeven   pinctrl: sh-pfc: ...
150
  		reg->shadow |= BIT(pos);
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
151
  	else
fc88936ad   Geert Uytterhoeven   pinctrl: sh-pfc: ...
152
  		reg->shadow &= ~BIT(pos);
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
153

51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
154
  	gpio_write_data_reg(chip, reg->info, reg->shadow);
b3c185a76   Paul Mundt   sh: pfc: Split ou...
155
  }
16883814e   Laurent Pinchart   sh-pfc: Split pin...
156
  static int gpio_pin_direction_input(struct gpio_chip *gc, unsigned offset)
ca5481c68   Paul Mundt   sh: pfc: Rudiment...
157
158
159
  {
  	return pinctrl_gpio_direction_input(offset);
  }
16883814e   Laurent Pinchart   sh-pfc: Split pin...
160
  static int gpio_pin_direction_output(struct gpio_chip *gc, unsigned offset,
ca5481c68   Paul Mundt   sh: pfc: Rudiment...
161
162
  				    int value)
  {
7cb093c4b   Linus Walleij   pinctrl: sh-pfc: ...
163
  	gpio_pin_set_value(gpiochip_get_data(gc), offset, value);
ca5481c68   Paul Mundt   sh: pfc: Rudiment...
164
165
166
  
  	return pinctrl_gpio_direction_output(offset);
  }
16883814e   Laurent Pinchart   sh-pfc: Split pin...
167
  static int gpio_pin_get(struct gpio_chip *gc, unsigned offset)
b3c185a76   Paul Mundt   sh: pfc: Split ou...
168
  {
7cb093c4b   Linus Walleij   pinctrl: sh-pfc: ...
169
  	struct sh_pfc_chip *chip = gpiochip_get_data(gc);
51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
170
  	struct sh_pfc_gpio_data_reg *reg;
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
171
  	unsigned int bit;
cef28a289   Geert Uytterhoeven   pinctrl: sh-pfc: ...
172
  	unsigned int pos;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
173

51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
174
  	gpio_get_data_reg(chip, offset, &reg, &bit);
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
175

51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
176
  	pos = reg->info->reg_width - (bit + 1);
41f1219fa   Laurent Pinchart   sh-pfc: Move GPIO...
177

51cb226b3   Laurent Pinchart   sh-pfc: Don't mod...
178
  	return (gpio_read_data_reg(chip, reg->info) >> pos) & 1;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
179
  }
16883814e   Laurent Pinchart   sh-pfc: Split pin...
180
  static void gpio_pin_set(struct gpio_chip *gc, unsigned offset, int value)
b3c185a76   Paul Mundt   sh: pfc: Split ou...
181
  {
7cb093c4b   Linus Walleij   pinctrl: sh-pfc: ...
182
  	gpio_pin_set_value(gpiochip_get_data(gc), offset, value);
b3c185a76   Paul Mundt   sh: pfc: Split ou...
183
  }
16883814e   Laurent Pinchart   sh-pfc: Split pin...
184
  static int gpio_pin_to_irq(struct gpio_chip *gc, unsigned offset)
b3c185a76   Paul Mundt   sh: pfc: Split ou...
185
186
  {
  	struct sh_pfc *pfc = gpio_to_pfc(gc);
8d72a7fc8   Laurent Pinchart   sh-pfc: Turn unsi...
187
  	unsigned int i, k;
c07f54f60   Laurent Pinchart   sh-pfc: Look up I...
188
189
  
  	for (i = 0; i < pfc->info->gpio_irq_size; i++) {
6d5bddd52   Laurent Pinchart   pinctrl: sh-pfc: ...
190
  		const short *gpios = pfc->info->gpio_irq[i].gpios;
c07f54f60   Laurent Pinchart   sh-pfc: Look up I...
191

316b25500   Laurent Pinchart   sh-pfc: Terminate...
192
  		for (k = 0; gpios[k] >= 0; k++) {
c07f54f60   Laurent Pinchart   sh-pfc: Look up I...
193
  			if (gpios[k] == offset)
70c8f01a3   Laurent Pinchart   sh-pfc: Support G...
194
  				goto found;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
195
196
  		}
  	}
9697643ff   Geert Uytterhoeven   pinctrl: sh-pfc: ...
197
  	return 0;
70c8f01a3   Laurent Pinchart   sh-pfc: Support G...
198
199
  
  found:
4adeabd04   Laurent Pinchart   pinctrl: sh-pfc: ...
200
  	return pfc->irqs[i];
b3c185a76   Paul Mundt   sh: pfc: Split ou...
201
  }
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
202
  static int gpio_pin_setup(struct sh_pfc_chip *chip)
b3c185a76   Paul Mundt   sh: pfc: Split ou...
203
204
205
  {
  	struct sh_pfc *pfc = chip->pfc;
  	struct gpio_chip *gc = &chip->gpio_chip;
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
206
  	int ret;
a1a3580cb   Laurent Pinchart   sh-pfc: Don't ove...
207
208
  	chip->pins = devm_kzalloc(pfc->dev, pfc->info->nr_pins *
  				  sizeof(*chip->pins), GFP_KERNEL);
1a0039dce   Laurent Pinchart   sh-pfc: Don't mod...
209
210
  	if (chip->pins == NULL)
  		return -ENOMEM;
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
211
212
213
  	ret = gpio_setup_data_regs(chip);
  	if (ret < 0)
  		return ret;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
214

16883814e   Laurent Pinchart   sh-pfc: Split pin...
215
216
217
218
219
220
221
  	gc->request = gpio_pin_request;
  	gc->free = gpio_pin_free;
  	gc->direction_input = gpio_pin_direction_input;
  	gc->get = gpio_pin_get;
  	gc->direction_output = gpio_pin_direction_output;
  	gc->set = gpio_pin_set;
  	gc->to_irq = gpio_pin_to_irq;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
222

19bb7fe36   Laurent Pinchart   sh-pfc: Support p...
223
  	gc->label = pfc->info->name;
58383c784   Linus Walleij   gpio: change memb...
224
  	gc->parent = pfc->dev;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
225
  	gc->owner = THIS_MODULE;
d7a7ca578   Laurent Pinchart   sh-pfc: Replace f...
226
  	gc->base = 0;
28818fa5d   Laurent Pinchart   sh-pfc: Rename st...
227
  	gc->ngpio = pfc->nr_gpio_pins;
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
228
229
  
  	return 0;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
230
  }
16883814e   Laurent Pinchart   sh-pfc: Split pin...
231
232
233
  /* -----------------------------------------------------------------------------
   * Function GPIOs
   */
56f891b46   Geert Uytterhoeven   pinctrl: sh-pfc: ...
234
  #ifdef CONFIG_SUPERH
16883814e   Laurent Pinchart   sh-pfc: Split pin...
235
236
  static int gpio_function_request(struct gpio_chip *gc, unsigned offset)
  {
9a643c9a1   Laurent Pinchart   sh-pfc: Convert m...
237
  	static bool __print_once;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
238
  	struct sh_pfc *pfc = gpio_to_pfc(gc);
a68fdca9b   Laurent Pinchart   sh-pfc: Use pinmu...
239
  	unsigned int mark = pfc->info->func_gpios[offset].enum_id;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
240
  	unsigned long flags;
b705c0542   Laurent Pinchart   sh-pfc: Use prope...
241
  	int ret;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
242

9a643c9a1   Laurent Pinchart   sh-pfc: Convert m...
243
244
245
246
247
248
249
  	if (!__print_once) {
  		dev_notice(pfc->dev,
  			   "Use of GPIO API for function requests is deprecated."
  			   " Convert to pinctrl
  ");
  		__print_once = true;
  	}
16883814e   Laurent Pinchart   sh-pfc: Split pin...
250

a68fdca9b   Laurent Pinchart   sh-pfc: Use pinmu...
251
  	if (mark == 0)
b705c0542   Laurent Pinchart   sh-pfc: Use prope...
252
  		return -EINVAL;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
253
254
  
  	spin_lock_irqsave(&pfc->lock, flags);
b705c0542   Laurent Pinchart   sh-pfc: Use prope...
255
  	ret = sh_pfc_config_mux(pfc, mark, PINMUX_TYPE_FUNCTION);
16883814e   Laurent Pinchart   sh-pfc: Split pin...
256
  	spin_unlock_irqrestore(&pfc->lock, flags);
b705c0542   Laurent Pinchart   sh-pfc: Use prope...
257

16883814e   Laurent Pinchart   sh-pfc: Split pin...
258
259
  	return ret;
  }
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
260
  static int gpio_function_setup(struct sh_pfc_chip *chip)
16883814e   Laurent Pinchart   sh-pfc: Split pin...
261
262
263
264
265
  {
  	struct sh_pfc *pfc = chip->pfc;
  	struct gpio_chip *gc = &chip->gpio_chip;
  
  	gc->request = gpio_function_request;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
266
267
268
  
  	gc->label = pfc->info->name;
  	gc->owner = THIS_MODULE;
28818fa5d   Laurent Pinchart   sh-pfc: Rename st...
269
  	gc->base = pfc->nr_gpio_pins;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
270
  	gc->ngpio = pfc->info->nr_func_gpios;
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
271
272
  
  	return 0;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
273
  }
56f891b46   Geert Uytterhoeven   pinctrl: sh-pfc: ...
274
  #endif
16883814e   Laurent Pinchart   sh-pfc: Split pin...
275
276
277
278
279
280
  
  /* -----------------------------------------------------------------------------
   * Register/unregister
   */
  
  static struct sh_pfc_chip *
ceef91dcc   Laurent Pinchart   sh-pfc: Skip gpio...
281
282
  sh_pfc_add_gpiochip(struct sh_pfc *pfc, int(*setup)(struct sh_pfc_chip *),
  		    struct sh_pfc_window *mem)
b3c185a76   Paul Mundt   sh: pfc: Split ou...
283
284
285
  {
  	struct sh_pfc_chip *chip;
  	int ret;
1724acfd5   Laurent Pinchart   sh-pfc: Use devm_...
286
  	chip = devm_kzalloc(pfc->dev, sizeof(*chip), GFP_KERNEL);
b3c185a76   Paul Mundt   sh: pfc: Split ou...
287
  	if (unlikely(!chip))
16883814e   Laurent Pinchart   sh-pfc: Split pin...
288
  		return ERR_PTR(-ENOMEM);
b3c185a76   Paul Mundt   sh: pfc: Split ou...
289

ceef91dcc   Laurent Pinchart   sh-pfc: Skip gpio...
290
  	chip->mem = mem;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
291
  	chip->pfc = pfc;
e51d5343f   Laurent Pinchart   sh-pfc: Don't map...
292
293
294
  	ret = setup(chip);
  	if (ret < 0)
  		return ERR_PTR(ret);
b3c185a76   Paul Mundt   sh: pfc: Split ou...
295

c29e2f2cb   Geert Uytterhoeven   pinctrl: sh-pfc: ...
296
  	ret = devm_gpiochip_add_data(pfc->dev, &chip->gpio_chip, chip);
1724acfd5   Laurent Pinchart   sh-pfc: Use devm_...
297
  	if (unlikely(ret < 0))
16883814e   Laurent Pinchart   sh-pfc: Split pin...
298
  		return ERR_PTR(ret);
9a643c9a1   Laurent Pinchart   sh-pfc: Convert m...
299
300
301
302
  	dev_info(pfc->dev, "%s handling gpio %u -> %u
  ",
  		 chip->gpio_chip.label, chip->gpio_chip.base,
  		 chip->gpio_chip.base + chip->gpio_chip.ngpio - 1);
16883814e   Laurent Pinchart   sh-pfc: Split pin...
303
304
305
306
307
308
309
  
  	return chip;
  }
  
  int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
  {
  	struct sh_pfc_chip *chip;
1f34de05e   Geert Uytterhoeven   pinctrl: sh-pfc: ...
310
  	phys_addr_t address;
63d573835   Laurent Pinchart   sh-pfc: Add suppo...
311
  	unsigned int i;
16883814e   Laurent Pinchart   sh-pfc: Split pin...
312

1a4fd58f7   Laurent Pinchart   sh-pfc: Make GPIO...
313
314
  	if (pfc->info->data_regs == NULL)
  		return 0;
ceef91dcc   Laurent Pinchart   sh-pfc: Skip gpio...
315
316
317
318
319
  	/* Find the memory window that contain the GPIO registers. Boards that
  	 * register a separate GPIO device will not supply a memory resource
  	 * that covers the data registers. In that case don't try to handle
  	 * GPIOs.
  	 */
1f34de05e   Geert Uytterhoeven   pinctrl: sh-pfc: ...
320
  	address = pfc->info->data_regs[0].reg;
ceef91dcc   Laurent Pinchart   sh-pfc: Skip gpio...
321
  	for (i = 0; i < pfc->num_windows; ++i) {
5b46ac3a7   Laurent Pinchart   sh-pfc: Rename sh...
322
  		struct sh_pfc_window *window = &pfc->windows[i];
ceef91dcc   Laurent Pinchart   sh-pfc: Skip gpio...
323

1f34de05e   Geert Uytterhoeven   pinctrl: sh-pfc: ...
324
325
  		if (address >= window->phys &&
  		    address < window->phys + window->size)
ceef91dcc   Laurent Pinchart   sh-pfc: Skip gpio...
326
327
328
329
330
  			break;
  	}
  
  	if (i == pfc->num_windows)
  		return 0;
70c8f01a3   Laurent Pinchart   sh-pfc: Support G...
331
  	/* If we have IRQ resources make sure their number is correct. */
4adeabd04   Laurent Pinchart   pinctrl: sh-pfc: ...
332
  	if (pfc->num_irqs != pfc->info->gpio_irq_size) {
70c8f01a3   Laurent Pinchart   sh-pfc: Support G...
333
334
335
336
  		dev_err(pfc->dev, "invalid number of IRQ resources
  ");
  		return -EINVAL;
  	}
63d573835   Laurent Pinchart   sh-pfc: Add suppo...
337
  	/* Register the real GPIOs chip. */
5b46ac3a7   Laurent Pinchart   sh-pfc: Rename sh...
338
  	chip = sh_pfc_add_gpiochip(pfc, gpio_pin_setup, &pfc->windows[i]);
16883814e   Laurent Pinchart   sh-pfc: Split pin...
339
340
  	if (IS_ERR(chip))
  		return PTR_ERR(chip);
6f6a4a683   Laurent Pinchart   sh-pfc: Merge PFC...
341
342
  
  	pfc->gpio = chip;
b3c185a76   Paul Mundt   sh: pfc: Split ou...
343

18fab3995   Geert Uytterhoeven   pinctrl: sh-pfc: ...
344
345
  	if (IS_ENABLED(CONFIG_OF) && pfc->dev->of_node)
  		return 0;
4f82e3ee7   Laurent Pinchart   sh-pfc: Support p...
346

90d066130   Geert Uytterhoeven   pinctrl: sh-pfc: ...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  #ifdef CONFIG_SUPERH
  	/*
  	 * Register the GPIO to pin mappings. As pins with GPIO ports
  	 * must come first in the ranges, skip the pins without GPIO
  	 * ports by stopping at the first range that contains such a
  	 * pin.
  	 */
  	for (i = 0; i < pfc->nr_ranges; ++i) {
  		const struct sh_pfc_pin_range *range = &pfc->ranges[i];
  		int ret;
  
  		if (range->start >= pfc->nr_gpio_pins)
  			break;
  
  		ret = gpiochip_add_pin_range(&chip->gpio_chip,
  			dev_name(pfc->dev), range->start, range->start,
  			range->end - range->start + 1);
  		if (ret < 0)
  			return ret;
63d573835   Laurent Pinchart   sh-pfc: Add suppo...
366
  	}
247127f90   Laurent Pinchart   sh-pfc: Replace p...
367

63d573835   Laurent Pinchart   sh-pfc: Add suppo...
368
  	/* Register the function GPIOs chip. */
542a564d2   Laurent Pinchart   sh-pfc: Make func...
369
370
  	if (pfc->info->nr_func_gpios == 0)
  		return 0;
ceef91dcc   Laurent Pinchart   sh-pfc: Skip gpio...
371
  	chip = sh_pfc_add_gpiochip(pfc, gpio_function_setup, NULL);
16883814e   Laurent Pinchart   sh-pfc: Split pin...
372
373
  	if (IS_ERR(chip))
  		return PTR_ERR(chip);
56f891b46   Geert Uytterhoeven   pinctrl: sh-pfc: ...
374
  #endif /* CONFIG_SUPERH */
b3c185a76   Paul Mundt   sh: pfc: Split ou...
375

b3c185a76   Paul Mundt   sh: pfc: Split ou...
376
377
  	return 0;
  }